xref: /libCEED/rust/libceed-sys/c-src/interface/ceed.c (revision fe2413ff2a5f6e0d0808f191532abb277c4b8bc7)
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>
20d7b241e6Sjeremylt #include <stdarg.h>
21d7b241e6Sjeremylt #include <stdio.h>
22d7b241e6Sjeremylt #include <stdlib.h>
23d7b241e6Sjeremylt #include <string.h>
24d7b241e6Sjeremylt 
25d7b241e6Sjeremylt /// @cond DOXYGEN_SKIP
26d7b241e6Sjeremylt static CeedRequest ceed_request_immediate;
27d7b241e6Sjeremylt static CeedRequest ceed_request_ordered;
28d7b241e6Sjeremylt 
29d7b241e6Sjeremylt static struct {
30d7b241e6Sjeremylt   char prefix[CEED_MAX_RESOURCE_LEN];
31d7b241e6Sjeremylt   int (*init)(const char *resource, Ceed f);
32d7b241e6Sjeremylt   unsigned int priority;
33d7b241e6Sjeremylt } backends[32];
34d7b241e6Sjeremylt static size_t num_backends;
35*fe2413ffSjeremylt 
36*fe2413ffSjeremylt #define ceedoffsetof(st, m) \
37*fe2413ffSjeremylt     ((size_t) ( (char *)&((st)(0))->m - (char *)0 ))
38d7b241e6Sjeremylt /// @endcond
39d7b241e6Sjeremylt 
40d7b241e6Sjeremylt /// @file
41d7b241e6Sjeremylt /// Implementation of core components of Ceed library
42d7b241e6Sjeremylt ///
43dfdf5a53Sjeremylt /// @addtogroup Ceed
44d7b241e6Sjeremylt /// @{
45d7b241e6Sjeremylt 
46dfdf5a53Sjeremylt /**
47dfdf5a53Sjeremylt   @brief Request immediate completion
48dfdf5a53Sjeremylt 
49dfdf5a53Sjeremylt   This predefined constant is passed as the \ref CeedRequest argument to
50dfdf5a53Sjeremylt   interfaces when the caller wishes for the operation to be performed
51dfdf5a53Sjeremylt   immediately.  The code
52dfdf5a53Sjeremylt 
53dfdf5a53Sjeremylt   @code
54dfdf5a53Sjeremylt     CeedOperatorApply(op, ..., CEED_REQUEST_IMMEDIATE);
55dfdf5a53Sjeremylt   @endcode
56dfdf5a53Sjeremylt 
57dfdf5a53Sjeremylt   is semantically equivalent to
58dfdf5a53Sjeremylt 
59dfdf5a53Sjeremylt   @code
60dfdf5a53Sjeremylt     CeedRequest request;
61dfdf5a53Sjeremylt     CeedOperatorApply(op, ..., &request);
62dfdf5a53Sjeremylt     CeedRequestWait(&request);
63dfdf5a53Sjeremylt   @endcode
64dfdf5a53Sjeremylt 
65dfdf5a53Sjeremylt   @sa CEED_REQUEST_ORDERED
66dfdf5a53Sjeremylt **/
67d7b241e6Sjeremylt CeedRequest *const CEED_REQUEST_IMMEDIATE = &ceed_request_immediate;
68d7b241e6Sjeremylt 
69d7b241e6Sjeremylt /**
70b11c1e72Sjeremylt   @brief Request ordered completion
71d7b241e6Sjeremylt 
72d7b241e6Sjeremylt   This predefined constant is passed as the \ref CeedRequest argument to
73d7b241e6Sjeremylt   interfaces when the caller wishes for the operation to be completed in the
74d7b241e6Sjeremylt   order that it is submitted to the device.  It is typically used in a construct
75d7b241e6Sjeremylt   such as
76d7b241e6Sjeremylt 
77d7b241e6Sjeremylt   @code
78d7b241e6Sjeremylt     CeedRequest request;
79d7b241e6Sjeremylt     CeedOperatorApply(op1, ..., CEED_REQUEST_ORDERED);
80d7b241e6Sjeremylt     CeedOperatorApply(op2, ..., &request);
81d7b241e6Sjeremylt     // other optional work
82d7b241e6Sjeremylt     CeedWait(&request);
83d7b241e6Sjeremylt   @endcode
84d7b241e6Sjeremylt 
85d7b241e6Sjeremylt   which allows the sequence to complete asynchronously but does not start
86d7b241e6Sjeremylt   `op2` until `op1` has completed.
87d7b241e6Sjeremylt 
88d7b241e6Sjeremylt   @fixme The current implementation is overly strict, offering equivalent
89d7b241e6Sjeremylt   semantics to CEED_REQUEST_IMMEDIATE.
90d7b241e6Sjeremylt 
91d7b241e6Sjeremylt   @sa CEED_REQUEST_IMMEDIATE
92d7b241e6Sjeremylt  */
93d7b241e6Sjeremylt CeedRequest *const CEED_REQUEST_ORDERED = &ceed_request_ordered;
94d7b241e6Sjeremylt 
95b11c1e72Sjeremylt /**
96b11c1e72Sjeremylt   @brief Error handling implementation; use \ref CeedError instead.
97dfdf5a53Sjeremylt 
98dfdf5a53Sjeremylt   @ref Developer
99b11c1e72Sjeremylt **/
100d7b241e6Sjeremylt int CeedErrorImpl(Ceed ceed, const char *filename, int lineno, const char *func,
101d7b241e6Sjeremylt                   int ecode, const char *format, ...) {
102d7b241e6Sjeremylt   va_list args;
103d7b241e6Sjeremylt   va_start(args, format);
104d7b241e6Sjeremylt   if (ceed) return ceed->Error(ceed, filename, lineno, func, ecode, format, args);
105d7b241e6Sjeremylt   return CeedErrorAbort(ceed, filename, lineno, func, ecode, format, args);
106d7b241e6Sjeremylt }
107d7b241e6Sjeremylt 
108b11c1e72Sjeremylt /**
109b11c1e72Sjeremylt   @brief Error handler that returns without printing anything.
110b11c1e72Sjeremylt 
111b11c1e72Sjeremylt   Pass this to CeedSetErrorHandler() to obtain this error handling behavior.
112dfdf5a53Sjeremylt 
113dfdf5a53Sjeremylt   @ref Developer
114b11c1e72Sjeremylt **/
115d7b241e6Sjeremylt int CeedErrorReturn(Ceed ceed, const char *filename, int lineno,
116d7b241e6Sjeremylt                     const char *func, int ecode, const char *format,
117d7b241e6Sjeremylt                     va_list args) {
118d7b241e6Sjeremylt   return ecode;
119d7b241e6Sjeremylt }
120d7b241e6Sjeremylt 
121b11c1e72Sjeremylt /**
122b11c1e72Sjeremylt   @brief Error handler that prints to stderr and aborts
123b11c1e72Sjeremylt 
124b11c1e72Sjeremylt   Pass this to CeedSetErrorHandler() to obtain this error handling behavior.
125dfdf5a53Sjeremylt 
126dfdf5a53Sjeremylt   @ref Developer
127b11c1e72Sjeremylt **/
128d7b241e6Sjeremylt int CeedErrorAbort(Ceed ceed, const char *filename, int lineno,
129d7b241e6Sjeremylt                    const char *func, int ecode,
130d7b241e6Sjeremylt                    const char *format, va_list args) {
131d7b241e6Sjeremylt   fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func);
132d7b241e6Sjeremylt   vfprintf(stderr, format, args);
133d7b241e6Sjeremylt   fprintf(stderr, "\n");
134d7b241e6Sjeremylt   abort();
135d7b241e6Sjeremylt   return ecode;
136d7b241e6Sjeremylt }
137d7b241e6Sjeremylt 
138b11c1e72Sjeremylt /**
13956e866f4SJed Brown   @brief Error handler that prints to stderr and exits
14056e866f4SJed Brown 
14156e866f4SJed Brown   Pass this to CeedSetErrorHandler() to obtain this error handling behavior.
14256e866f4SJed Brown 
14356e866f4SJed Brown   In contrast to CeedErrorAbort(), this exits without a signal, so atexit()
14456e866f4SJed Brown   handlers (e.g., as used by gcov) are run.
14556e866f4SJed Brown 
14656e866f4SJed Brown   @ref Developer
14756e866f4SJed Brown **/
14856e866f4SJed Brown int CeedErrorExit(Ceed ceed, const char *filename, int lineno,
14956e866f4SJed Brown                   const char *func, int ecode,
15056e866f4SJed Brown                   const char *format, va_list args) {
15156e866f4SJed Brown   fprintf(stderr, "%s:%d in %s(): ", filename, lineno, func);
15256e866f4SJed Brown   vfprintf(stderr, format, args);
15356e866f4SJed Brown   fprintf(stderr, "\n");
15456e866f4SJed Brown   exit(ecode);
15556e866f4SJed Brown   return ecode;
15656e866f4SJed Brown }
15756e866f4SJed Brown 
15856e866f4SJed Brown /**
159dfdf5a53Sjeremylt   @brief Set error handler
160b11c1e72Sjeremylt 
161b11c1e72Sjeremylt   A default error handler is set in CeedInit().  Use this function to change
162b11c1e72Sjeremylt   the error handler to CeedErrorReturn(), CeedErrorAbort(), or a user-defined
163b11c1e72Sjeremylt   error handler.
164dfdf5a53Sjeremylt 
165dfdf5a53Sjeremylt   @ref Developer
166b11c1e72Sjeremylt **/
167d7b241e6Sjeremylt int CeedSetErrorHandler(Ceed ceed,
168d7b241e6Sjeremylt                         int (eh)(Ceed, const char *, int, const char *,
169d7b241e6Sjeremylt                                  int, const char *, va_list)) {
170d7b241e6Sjeremylt   ceed->Error = eh;
171d7b241e6Sjeremylt   return 0;
172d7b241e6Sjeremylt }
173d7b241e6Sjeremylt 
174d7b241e6Sjeremylt /**
175b11c1e72Sjeremylt   @brief Register a Ceed backend
176d7b241e6Sjeremylt 
177d7b241e6Sjeremylt   @param prefix   Prefix of resources for this backend to respond to.  For
178d7b241e6Sjeremylt                     example, the reference backend responds to "/cpu/self".
179d7b241e6Sjeremylt   @param init     Initialization function called by CeedInit() when the backend
180d7b241e6Sjeremylt                     is selected to drive the requested resource.
181d7b241e6Sjeremylt   @param priority Integer priority.  Lower values are preferred in case the
182d7b241e6Sjeremylt                     resource requested by CeedInit() has non-unique best prefix
183d7b241e6Sjeremylt                     match.
184b11c1e72Sjeremylt 
185b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
186dfdf5a53Sjeremylt 
187dfdf5a53Sjeremylt   @ref Advanced
188b11c1e72Sjeremylt **/
189d7b241e6Sjeremylt int CeedRegister(const char *prefix,
190d7b241e6Sjeremylt                  int (*init)(const char *, Ceed), unsigned int priority) {
191d7b241e6Sjeremylt   if (num_backends >= sizeof(backends) / sizeof(backends[0])) {
192d7b241e6Sjeremylt     return CeedError(NULL, 1, "Too many backends");
193d7b241e6Sjeremylt   }
194d7b241e6Sjeremylt   strncpy(backends[num_backends].prefix, prefix, CEED_MAX_RESOURCE_LEN);
195d7b241e6Sjeremylt   backends[num_backends].init = init;
196d7b241e6Sjeremylt   backends[num_backends].priority = priority;
197d7b241e6Sjeremylt   num_backends++;
198d7b241e6Sjeremylt   return 0;
199d7b241e6Sjeremylt }
200d7b241e6Sjeremylt 
201b11c1e72Sjeremylt /**
202b11c1e72Sjeremylt   @brief Allocate an array on the host; use CeedMalloc()
203b11c1e72Sjeremylt 
204b11c1e72Sjeremylt   Memory usage can be tracked by the library.  This ensures sufficient
205b11c1e72Sjeremylt     alignment for vectorization and should be used for large allocations.
206b11c1e72Sjeremylt 
207b11c1e72Sjeremylt   @param n Number of units to allocate
208b11c1e72Sjeremylt   @param unit Size of each unit
209b11c1e72Sjeremylt   @param p Address of pointer to hold the result.
210b11c1e72Sjeremylt 
211b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
212b11c1e72Sjeremylt 
213b11c1e72Sjeremylt   @sa CeedFree()
214dfdf5a53Sjeremylt 
215dfdf5a53Sjeremylt   @ref Advanced
216b11c1e72Sjeremylt **/
217d7b241e6Sjeremylt int CeedMallocArray(size_t n, size_t unit, void *p) {
218d7b241e6Sjeremylt   int ierr = posix_memalign((void **)p, CEED_ALIGN, n*unit);
219d7b241e6Sjeremylt   if (ierr)
220d7b241e6Sjeremylt     return CeedError(NULL, ierr,
221d7b241e6Sjeremylt                      "posix_memalign failed to allocate %zd members of size %zd\n", n, unit);
222d7b241e6Sjeremylt   return 0;
223d7b241e6Sjeremylt }
224d7b241e6Sjeremylt 
225b11c1e72Sjeremylt /**
226b11c1e72Sjeremylt   @brief Allocate a cleared (zeroed) array on the host; use CeedCalloc()
227b11c1e72Sjeremylt 
228b11c1e72Sjeremylt   Memory usage can be tracked by the library.
229b11c1e72Sjeremylt 
230b11c1e72Sjeremylt   @param n Number of units to allocate
231b11c1e72Sjeremylt   @param unit Size of each unit
232b11c1e72Sjeremylt   @param p Address of pointer to hold the result.
233b11c1e72Sjeremylt 
234b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
235b11c1e72Sjeremylt 
236b11c1e72Sjeremylt   @sa CeedFree()
237dfdf5a53Sjeremylt 
238dfdf5a53Sjeremylt   @ref Advanced
239b11c1e72Sjeremylt **/
240d7b241e6Sjeremylt int CeedCallocArray(size_t n, size_t unit, void *p) {
241d7b241e6Sjeremylt   *(void **)p = calloc(n, unit);
242d7b241e6Sjeremylt   if (n && unit && !*(void **)p)
243d7b241e6Sjeremylt     return CeedError(NULL, 1, "calloc failed to allocate %zd members of size %zd\n",
244d7b241e6Sjeremylt                      n, unit);
245d7b241e6Sjeremylt   return 0;
246d7b241e6Sjeremylt }
247d7b241e6Sjeremylt 
248b11c1e72Sjeremylt /**
249b11c1e72Sjeremylt   @brief Reallocate an array on the host; use CeedRealloc()
250b11c1e72Sjeremylt 
251b11c1e72Sjeremylt   Memory usage can be tracked by the library.
252b11c1e72Sjeremylt 
253b11c1e72Sjeremylt   @param n Number of units to allocate
254b11c1e72Sjeremylt   @param unit Size of each unit
255b11c1e72Sjeremylt   @param p Address of pointer to hold the result.
256b11c1e72Sjeremylt 
257b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
258b11c1e72Sjeremylt 
259b11c1e72Sjeremylt   @sa CeedFree()
260dfdf5a53Sjeremylt 
261dfdf5a53Sjeremylt   @ref Advanced
262b11c1e72Sjeremylt **/
263d7b241e6Sjeremylt int CeedReallocArray(size_t n, size_t unit, void *p) {
264d7b241e6Sjeremylt   *(void **)p = realloc(*(void **)p, n*unit);
265d7b241e6Sjeremylt   if (n && unit && !*(void **)p)
266d7b241e6Sjeremylt     return CeedError(NULL, 1,
267d7b241e6Sjeremylt                      "realloc failed to allocate %zd members of size %zd\n",
268d7b241e6Sjeremylt                      n, unit);
269d7b241e6Sjeremylt   return 0;
270d7b241e6Sjeremylt }
271d7b241e6Sjeremylt 
272d7b241e6Sjeremylt /// Free memory allocated using CeedMalloc() or CeedCalloc()
273d7b241e6Sjeremylt ///
274d7b241e6Sjeremylt /// @param p address of pointer to memory.  This argument is of type void* to
275d7b241e6Sjeremylt /// avoid needing a cast, but is the address of the pointer (which is zeroed)
276d7b241e6Sjeremylt /// rather than the pointer.
277d7b241e6Sjeremylt int CeedFree(void *p) {
278d7b241e6Sjeremylt   free(*(void **)p);
279d7b241e6Sjeremylt   *(void **)p = NULL;
280d7b241e6Sjeremylt   return 0;
281d7b241e6Sjeremylt }
282d7b241e6Sjeremylt 
283d7b241e6Sjeremylt /**
284b11c1e72Sjeremylt   @brief Wait for a CeedRequest to complete.
285d7b241e6Sjeremylt 
286d7b241e6Sjeremylt   Calling CeedRequestWait on a NULL request is a no-op.
287d7b241e6Sjeremylt 
288d7b241e6Sjeremylt   @param req Address of CeedRequest to wait for; zeroed on completion.
289b11c1e72Sjeremylt 
290b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
291dfdf5a53Sjeremylt 
292dfdf5a53Sjeremylt   @ref Advanced
293b11c1e72Sjeremylt **/
294d7b241e6Sjeremylt int CeedRequestWait(CeedRequest *req) {
295d7b241e6Sjeremylt   if (!*req) return 0;
296d7b241e6Sjeremylt   return CeedError(NULL, 2, "CeedRequestWait not implemented");
297d7b241e6Sjeremylt }
298d7b241e6Sjeremylt 
299b11c1e72Sjeremylt /**
300b11c1e72Sjeremylt   @brief Initialize a \ref Ceed to use the specified resource.
301b11c1e72Sjeremylt 
302b11c1e72Sjeremylt   @param resource  Resource to use, e.g., "/cpu/self"
303b11c1e72Sjeremylt   @param ceed The library context
304b11c1e72Sjeremylt   @sa CeedRegister() CeedDestroy()
305b11c1e72Sjeremylt 
306b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
307dfdf5a53Sjeremylt 
308dfdf5a53Sjeremylt   @ref Basic
309b11c1e72Sjeremylt **/
310d7b241e6Sjeremylt int CeedInit(const char *resource, Ceed *ceed) {
311d7b241e6Sjeremylt   int ierr;
312d7b241e6Sjeremylt   size_t matchlen = 0, matchidx;
313d7b241e6Sjeremylt   unsigned int matchpriority = 100, priority;
314d7b241e6Sjeremylt 
315*fe2413ffSjeremylt   // 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");
329*fe2413ffSjeremylt 
330*fe2413ffSjeremylt   // 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;
340*fe2413ffSjeremylt 
341*fe2413ffSjeremylt   // Set lookup table
342*fe2413ffSjeremylt   foffset foffsets[25] = {
343*fe2413ffSjeremylt       {"Error",                  ceedoffsetof(Ceed, Error)},
344*fe2413ffSjeremylt       {"CeedDestroy",            ceedoffsetof(Ceed, Destroy)},
345*fe2413ffSjeremylt       {"VecCreate",              ceedoffsetof(Ceed, VecCreate)},
346*fe2413ffSjeremylt       {"ElemRestrictionCreate",  ceedoffsetof(Ceed, ElemRestrictionCreate)},
347*fe2413ffSjeremylt       {"ElemRestrictionCreateBlocked",
348*fe2413ffSjeremylt                                  ceedoffsetof(Ceed, ElemRestrictionCreateBlocked)},
349*fe2413ffSjeremylt       {"BasisCreateTensorH1",    ceedoffsetof(Ceed, BasisCreateTensorH1)},
350*fe2413ffSjeremylt       {"BasisCreateH1",          ceedoffsetof(Ceed, BasisCreateH1)},
351*fe2413ffSjeremylt       {"QFunctionCreate",        ceedoffsetof(Ceed, QFunctionCreate)},
352*fe2413ffSjeremylt       {"OperatorCreate",         ceedoffsetof(Ceed, OperatorCreate)},
353*fe2413ffSjeremylt       {"SetArray",               ceedoffsetof(CeedVector, SetArray)},
354*fe2413ffSjeremylt       {"SetValue",               ceedoffsetof(CeedVector, SetValue)},
355*fe2413ffSjeremylt       {"GetArray",               ceedoffsetof(CeedVector, GetArray)},
356*fe2413ffSjeremylt       {"GetArrayRead",           ceedoffsetof(CeedVector, GetArrayRead)},
357*fe2413ffSjeremylt       {"RestoreArray",           ceedoffsetof(CeedVector, RestoreArray)},
358*fe2413ffSjeremylt       {"RestoreArrayRead",       ceedoffsetof(CeedVector, RestoreArrayRead)},
359*fe2413ffSjeremylt       {"VectorDestroy",          ceedoffsetof(CeedVector, Destroy)},
360*fe2413ffSjeremylt       {"ElemRestrictionApply",   ceedoffsetof(CeedElemRestriction, Apply)},
361*fe2413ffSjeremylt       {"ElemRestrictionDestroy", ceedoffsetof(CeedElemRestriction, Destroy)},
362*fe2413ffSjeremylt       {"BasisApply",             ceedoffsetof(CeedBasis, Apply)},
363*fe2413ffSjeremylt       {"BasisDestroy",           ceedoffsetof(CeedBasis, Destroy)},
364*fe2413ffSjeremylt       {"QFunctionApply",         ceedoffsetof(CeedQFunction, Apply)},
365*fe2413ffSjeremylt       {"QFunctionDestroy",       ceedoffsetof(CeedQFunction, Destroy)},
366*fe2413ffSjeremylt       {"OperatorApply",          ceedoffsetof(CeedOperator, Apply)},
367*fe2413ffSjeremylt       {"ApplyJacobian",          ceedoffsetof(CeedOperator, ApplyJacobian)},
368*fe2413ffSjeremylt       {"OperatorDestroy",        ceedoffsetof(CeedOperator, Destroy)}         };
369*fe2413ffSjeremylt 
370*fe2413ffSjeremylt   memcpy((*ceed)->foffsets, foffsets, 25*sizeof(foffset));
371*fe2413ffSjeremylt 
372*fe2413ffSjeremylt   // Backend specific setup
373d7b241e6Sjeremylt   ierr = backends[matchidx].init(resource, *ceed); CeedChk(ierr);
374*fe2413ffSjeremylt 
375d7b241e6Sjeremylt   return 0;
376d7b241e6Sjeremylt }
377d7b241e6Sjeremylt 
378d7b241e6Sjeremylt /**
3795fe0d4faSjeremylt   @brief Retrieve a delegate CEED
3805fe0d4faSjeremylt 
3815fe0d4faSjeremylt   @param ceed           Ceed to retrieve delegate of
3825fe0d4faSjeremylt   @param[out] delegate  Address to save the delegate to
3835fe0d4faSjeremylt 
3845fe0d4faSjeremylt   @return An error code: 0 - success, otherwise - failure
3855fe0d4faSjeremylt 
38623617272Sjeremylt   @ref Developer
3875fe0d4faSjeremylt **/
3885fe0d4faSjeremylt int CeedGetDelegate(Ceed ceed, Ceed *delegate) {
3894ce2993fSjeremylt   *delegate = ceed->delegate;
3904ce2993fSjeremylt   return 0;
3914ce2993fSjeremylt }
3924ce2993fSjeremylt 
3934ce2993fSjeremylt /**
3944ce2993fSjeremylt   @brief Set a delegate CEED
3954ce2993fSjeremylt 
3964ce2993fSjeremylt   @param ceed           Ceed to set delegate of
3974ce2993fSjeremylt   @param[out] delegate  Address to set the delegate to
3984ce2993fSjeremylt 
3994ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
4004ce2993fSjeremylt 
40123617272Sjeremylt   @ref Advanced
4024ce2993fSjeremylt **/
4034ce2993fSjeremylt int CeedSetDelegate(Ceed ceed, Ceed *delegate) {
4044ce2993fSjeremylt   ceed->delegate = *delegate;
4054ce2993fSjeremylt   return 0;
4064ce2993fSjeremylt }
4074ce2993fSjeremylt 
4084ce2993fSjeremylt /**
409*fe2413ffSjeremylt   @brief Set a backend function
410*fe2413ffSjeremylt 
411*fe2413ffSjeremylt   @param ceed           Ceed for error handling
412*fe2413ffSjeremylt   @param type           Type of Ceed object to set function for
413*fe2413ffSjeremylt   @param[out] object    Ceed object to set function for
414*fe2413ffSjeremylt   @param fname          Name of function to set
415*fe2413ffSjeremylt   @param f              Function to set
416*fe2413ffSjeremylt 
417*fe2413ffSjeremylt   @return An error code: 0 - success, otherwise - failure
418*fe2413ffSjeremylt 
419*fe2413ffSjeremylt   @ref Advanced
420*fe2413ffSjeremylt **/
421*fe2413ffSjeremylt int CeedSetBackendFunction(Ceed ceed,
422*fe2413ffSjeremylt                            const char *type, void *object,
423*fe2413ffSjeremylt                            const char *fname, int (*f)()) {
424*fe2413ffSjeremylt   char lookupname[100];
425*fe2413ffSjeremylt   strcpy(lookupname, "");
426*fe2413ffSjeremylt 
427*fe2413ffSjeremylt   // Build lookup name
428*fe2413ffSjeremylt   if (!strcmp(fname, "Apply") || !strcmp(fname, "Destroy")) {
429*fe2413ffSjeremylt     strcat(strcat(lookupname, type), fname);
430*fe2413ffSjeremylt   } else {
431*fe2413ffSjeremylt     strcat(lookupname, fname);
432*fe2413ffSjeremylt   }
433*fe2413ffSjeremylt 
434*fe2413ffSjeremylt   // Find and use offset
435*fe2413ffSjeremylt   for (CeedInt i = 0; i < 25; i++) {
436*fe2413ffSjeremylt     if (!strcmp(ceed->foffsets[i].fname, lookupname)) {
437*fe2413ffSjeremylt       size_t offset = ceed->foffsets[i].offset;
438*fe2413ffSjeremylt       size_t *fpointer;
439*fe2413ffSjeremylt       fpointer = (size_t *)(object + offset);
440*fe2413ffSjeremylt       *fpointer = (size_t) f;
441*fe2413ffSjeremylt       return 0;
442*fe2413ffSjeremylt     }
443*fe2413ffSjeremylt   }
444*fe2413ffSjeremylt 
445*fe2413ffSjeremylt   return CeedError(ceed, 1, "Requested function '%s' was not found", fname);
446*fe2413ffSjeremylt }
447*fe2413ffSjeremylt 
448*fe2413ffSjeremylt /**
4494ce2993fSjeremylt   @brief Retrieve backend data for a CEED
4504ce2993fSjeremylt 
451*fe2413ffSjeremylt   @param ceed           Ceed to retrieve data of
4524ce2993fSjeremylt   @param[out] data      Address to save data to
4534ce2993fSjeremylt 
4544ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
4554ce2993fSjeremylt 
45623617272Sjeremylt   @ref Advanced
4574ce2993fSjeremylt **/
4584ce2993fSjeremylt int CeedGetData(Ceed ceed, void* *data) {
4594ce2993fSjeremylt   *data = ceed->data;
4605fe0d4faSjeremylt   return 0;
4615fe0d4faSjeremylt }
4625fe0d4faSjeremylt 
4635fe0d4faSjeremylt /**
464*fe2413ffSjeremylt   @brief Set backend data for a CEED
465*fe2413ffSjeremylt 
466*fe2413ffSjeremylt   @param ceed           Ceed to set data of
467*fe2413ffSjeremylt   @param data           Address of data to set
468*fe2413ffSjeremylt 
469*fe2413ffSjeremylt   @return An error code: 0 - success, otherwise - failure
470*fe2413ffSjeremylt 
471*fe2413ffSjeremylt   @ref Advanced
472*fe2413ffSjeremylt **/
473*fe2413ffSjeremylt int CeedSetData(Ceed ceed, void* *data) {
474*fe2413ffSjeremylt   ceed->data = *data;
475*fe2413ffSjeremylt   return 0;
476*fe2413ffSjeremylt }
477*fe2413ffSjeremylt 
478*fe2413ffSjeremylt /**
479b11c1e72Sjeremylt   @brief Destroy a Ceed context
480d7b241e6Sjeremylt 
481d7b241e6Sjeremylt   @param ceed Address of Ceed context to destroy
482b11c1e72Sjeremylt 
483b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
484dfdf5a53Sjeremylt 
485dfdf5a53Sjeremylt   @ref Basic
486b11c1e72Sjeremylt **/
487d7b241e6Sjeremylt int CeedDestroy(Ceed *ceed) {
488d7b241e6Sjeremylt   int ierr;
489d7b241e6Sjeremylt 
490d7b241e6Sjeremylt   if (!*ceed || --(*ceed)->refcount > 0) return 0;
4915fe0d4faSjeremylt   if ((*ceed)->delegate) {
4925fe0d4faSjeremylt     ierr = CeedDestroy(&(*ceed)->delegate); CeedChk(ierr);
4935fe0d4faSjeremylt   }
494d7b241e6Sjeremylt   if ((*ceed)->Destroy) {
495d7b241e6Sjeremylt     ierr = (*ceed)->Destroy(*ceed); CeedChk(ierr);
496d7b241e6Sjeremylt   }
497d7b241e6Sjeremylt   ierr = CeedFree(ceed); CeedChk(ierr);
498d7b241e6Sjeremylt   return 0;
499d7b241e6Sjeremylt }
500d7b241e6Sjeremylt 
501d7b241e6Sjeremylt /// @}
502