xref: /libCEED/rust/libceed-sys/c-src/interface/ceed.c (revision 9c774eddf8c0b4f5416196d32c5355c9591a7190)
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
18ec3da8bcSJed Brown #include <ceed/ceed.h>
19ec3da8bcSJed Brown #include <ceed/backend.h>
203d576824SJeremy L Thompson #include <ceed-impl.h>
21aedaa0e5Sjeremylt #include <limits.h>
22d7b241e6Sjeremylt #include <stdarg.h>
236e79d475Sjeremylt #include <stddef.h>
24d7b241e6Sjeremylt #include <stdio.h>
25d7b241e6Sjeremylt #include <stdlib.h>
26d7b241e6Sjeremylt #include <string.h>
27d7b241e6Sjeremylt 
28d7b241e6Sjeremylt /// @cond DOXYGEN_SKIP
29d7b241e6Sjeremylt static CeedRequest ceed_request_immediate;
30d7b241e6Sjeremylt static CeedRequest ceed_request_ordered;
31d7b241e6Sjeremylt 
32d7b241e6Sjeremylt static struct {
33d7b241e6Sjeremylt   char prefix[CEED_MAX_RESOURCE_LEN];
34d7b241e6Sjeremylt   int (*init)(const char *resource, Ceed f);
35d7b241e6Sjeremylt   unsigned int priority;
36d7b241e6Sjeremylt } backends[32];
37d7b241e6Sjeremylt static size_t num_backends;
38fe2413ffSjeremylt 
396e79d475Sjeremylt #define CEED_FTABLE_ENTRY(class, method) \
406e79d475Sjeremylt   {#class #method, offsetof(struct class ##_private, method)}
41d7b241e6Sjeremylt /// @endcond
42d7b241e6Sjeremylt 
43d7b241e6Sjeremylt /// @file
44d7b241e6Sjeremylt /// Implementation of core components of Ceed library
457a982d89SJeremy L. Thompson 
467a982d89SJeremy L. Thompson /// @addtogroup CeedUser
47d7b241e6Sjeremylt /// @{
48d7b241e6Sjeremylt 
49dfdf5a53Sjeremylt /**
50dfdf5a53Sjeremylt   @brief Request immediate completion
51dfdf5a53Sjeremylt 
52dfdf5a53Sjeremylt   This predefined constant is passed as the \ref CeedRequest argument to
53dfdf5a53Sjeremylt   interfaces when the caller wishes for the operation to be performed
54dfdf5a53Sjeremylt   immediately.  The code
55dfdf5a53Sjeremylt 
56dfdf5a53Sjeremylt   @code
57dfdf5a53Sjeremylt     CeedOperatorApply(op, ..., CEED_REQUEST_IMMEDIATE);
58dfdf5a53Sjeremylt   @endcode
59dfdf5a53Sjeremylt 
60dfdf5a53Sjeremylt   is semantically equivalent to
61dfdf5a53Sjeremylt 
62dfdf5a53Sjeremylt   @code
63dfdf5a53Sjeremylt     CeedRequest request;
64dfdf5a53Sjeremylt     CeedOperatorApply(op, ..., &request);
65dfdf5a53Sjeremylt     CeedRequestWait(&request);
66dfdf5a53Sjeremylt   @endcode
67dfdf5a53Sjeremylt 
68dfdf5a53Sjeremylt   @sa CEED_REQUEST_ORDERED
69dfdf5a53Sjeremylt **/
70d7b241e6Sjeremylt CeedRequest *const CEED_REQUEST_IMMEDIATE = &ceed_request_immediate;
71d7b241e6Sjeremylt 
72d7b241e6Sjeremylt /**
73b11c1e72Sjeremylt   @brief Request ordered completion
74d7b241e6Sjeremylt 
75d7b241e6Sjeremylt   This predefined constant is passed as the \ref CeedRequest argument to
76d7b241e6Sjeremylt   interfaces when the caller wishes for the operation to be completed in the
77d7b241e6Sjeremylt   order that it is submitted to the device.  It is typically used in a construct
78d7b241e6Sjeremylt   such as
79d7b241e6Sjeremylt 
80d7b241e6Sjeremylt   @code
81d7b241e6Sjeremylt     CeedRequest request;
82d7b241e6Sjeremylt     CeedOperatorApply(op1, ..., CEED_REQUEST_ORDERED);
83d7b241e6Sjeremylt     CeedOperatorApply(op2, ..., &request);
84d7b241e6Sjeremylt     // other optional work
858b2d6f4aSMatthew Knepley     CeedRequestWait(&request);
86d7b241e6Sjeremylt   @endcode
87d7b241e6Sjeremylt 
88d7b241e6Sjeremylt   which allows the sequence to complete asynchronously but does not start
89d7b241e6Sjeremylt   `op2` until `op1` has completed.
90d7b241e6Sjeremylt 
91288c0443SJeremy L Thompson   @todo The current implementation is overly strict, offering equivalent
924cc79fe7SJed Brown   semantics to @ref CEED_REQUEST_IMMEDIATE.
93d7b241e6Sjeremylt 
94d7b241e6Sjeremylt   @sa CEED_REQUEST_IMMEDIATE
95d7b241e6Sjeremylt  */
96d7b241e6Sjeremylt CeedRequest *const CEED_REQUEST_ORDERED = &ceed_request_ordered;
97d7b241e6Sjeremylt 
98b11c1e72Sjeremylt /**
997a982d89SJeremy L. Thompson   @brief Wait for a CeedRequest to complete.
100dfdf5a53Sjeremylt 
1017a982d89SJeremy L. Thompson   Calling CeedRequestWait on a NULL request is a no-op.
1027a982d89SJeremy L. Thompson 
1037a982d89SJeremy L. Thompson   @param req Address of CeedRequest to wait for; zeroed on completion.
1047a982d89SJeremy L. Thompson 
1057a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1067a982d89SJeremy L. Thompson 
1077a982d89SJeremy L. Thompson   @ref User
108b11c1e72Sjeremylt **/
1097a982d89SJeremy L. Thompson int CeedRequestWait(CeedRequest *req) {
1107a982d89SJeremy L. Thompson   if (!*req)
111e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
112e15f9bd0SJeremy L Thompson   return CeedError(NULL, CEED_ERROR_UNSUPPORTED,
113e15f9bd0SJeremy L Thompson                    "CeedRequestWait not implemented");
114683faae0SJed Brown }
1157a982d89SJeremy L. Thompson 
1167a982d89SJeremy L. Thompson /// @}
1177a982d89SJeremy L. Thompson 
1187a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
1197a982d89SJeremy L. Thompson /// Ceed Library Internal Functions
1207a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
1217a982d89SJeremy L. Thompson /// @addtogroup CeedDeveloper
1227a982d89SJeremy L. Thompson /// @{
123d7b241e6Sjeremylt 
1246a406739SJeremy L Thompson /**
1256a406739SJeremy L Thompson   @brief Register a Ceed backend internally.
1266a406739SJeremy L Thompson            Note: Backends should call `CeedRegister` instead.
1276a406739SJeremy L Thompson 
1286a406739SJeremy L Thompson   @param prefix    Prefix of resources for this backend to respond to.  For
1296a406739SJeremy L Thompson                      example, the reference backend responds to "/cpu/self".
1306a406739SJeremy L Thompson   @param init      Initialization function called by CeedInit() when the backend
1316a406739SJeremy L Thompson                      is selected to drive the requested resource.
1326a406739SJeremy L Thompson   @param priority  Integer priority.  Lower values are preferred in case the
1336a406739SJeremy L Thompson                      resource requested by CeedInit() has non-unique best prefix
1346a406739SJeremy L Thompson                      match.
1356a406739SJeremy L Thompson 
1366a406739SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1376a406739SJeremy L Thompson 
1386a406739SJeremy L Thompson   @ref Developer
1396a406739SJeremy L Thompson **/
1406a406739SJeremy L Thompson int CeedRegisterImpl(const char *prefix, int (*init)(const char *, Ceed),
1416a406739SJeremy L Thompson                      unsigned int priority) {
1426a406739SJeremy L Thompson   if (num_backends >= sizeof(backends) / sizeof(backends[0]))
1436a406739SJeremy L Thompson     // LCOV_EXCL_START
1446a406739SJeremy L Thompson     return CeedError(NULL, CEED_ERROR_MAJOR, "Too many backends");
1456a406739SJeremy L Thompson   // LCOV_EXCL_STOP
1466a406739SJeremy L Thompson 
1476a406739SJeremy L Thompson   strncpy(backends[num_backends].prefix, prefix, CEED_MAX_RESOURCE_LEN);
1486a406739SJeremy L Thompson   backends[num_backends].prefix[CEED_MAX_RESOURCE_LEN-1] = 0;
1496a406739SJeremy L Thompson   backends[num_backends].init = init;
1506a406739SJeremy L Thompson   backends[num_backends].priority = priority;
1516a406739SJeremy L Thompson   num_backends++;
1526a406739SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1536a406739SJeremy L Thompson }
1546a406739SJeremy L Thompson 
1557a982d89SJeremy L. Thompson /// @}
156d7b241e6Sjeremylt 
1577a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
1587a982d89SJeremy L. Thompson /// Ceed Backend API
1597a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
1607a982d89SJeremy L. Thompson /// @addtogroup CeedBackend
1617a982d89SJeremy L. Thompson /// @{
162d7b241e6Sjeremylt 
163b11c1e72Sjeremylt /**
1643f21f6b1SJeremy L Thompson   @brief Return value of CEED_DEBUG environment variable
16560f9e2d6SJeremy L Thompson 
16660f9e2d6SJeremy L Thompson   @param ceed    Ceed context
16760f9e2d6SJeremy L Thompson 
1683f21f6b1SJeremy L Thompson   @return boolean value: true  - debugging mode enabled
1693f21f6b1SJeremy L Thompson                          false - debugging mode disabled
17060f9e2d6SJeremy L Thompson 
17160f9e2d6SJeremy L Thompson   @ref Backend
17260f9e2d6SJeremy L Thompson **/
173fc6bbcedSJeremy L Thompson // LCOV_EXCL_START
1743f21f6b1SJeremy L Thompson bool CeedDebugFlag(const Ceed ceed) {
1753f21f6b1SJeremy L Thompson   return ceed->is_debug;
17660f9e2d6SJeremy L Thompson }
177fc6bbcedSJeremy L Thompson // LCOV_EXCL_STOP
17860f9e2d6SJeremy L Thompson 
17960f9e2d6SJeremy L Thompson /**
1803f21f6b1SJeremy L Thompson   @brief Return value of CEED_DEBUG environment variable
18160f9e2d6SJeremy L Thompson 
1823f21f6b1SJeremy L Thompson   @return boolean value: true  - debugging mode enabled
1833f21f6b1SJeremy L Thompson                          false - debugging mode disabled
1843f21f6b1SJeremy L Thompson 
1853f21f6b1SJeremy L Thompson   @ref Backend
1863f21f6b1SJeremy L Thompson **/
1873f21f6b1SJeremy L Thompson // LCOV_EXCL_START
1883f21f6b1SJeremy L Thompson bool CeedDebugFlagEnv(void) {
1893f21f6b1SJeremy L Thompson   return !!getenv("CEED_DEBUG") || !!getenv("DEBUG") || !!getenv("DBG");
1903f21f6b1SJeremy L Thompson }
1913f21f6b1SJeremy L Thompson // LCOV_EXCL_STOP
1923f21f6b1SJeremy L Thompson 
1933f21f6b1SJeremy L Thompson /**
1943f21f6b1SJeremy L Thompson   @brief Print debugging information in color
1953f21f6b1SJeremy L Thompson 
19660f9e2d6SJeremy L Thompson   @param color   Color to print
19760f9e2d6SJeremy L Thompson   @param format  Printing format
19860f9e2d6SJeremy L Thompson 
19960f9e2d6SJeremy L Thompson   @return None
20060f9e2d6SJeremy L Thompson 
20160f9e2d6SJeremy L Thompson   @ref Backend
20260f9e2d6SJeremy L Thompson **/
203fc6bbcedSJeremy L Thompson // LCOV_EXCL_START
2043f21f6b1SJeremy L Thompson void CeedDebugImpl256(const unsigned char color, const char *format,...) {
20560f9e2d6SJeremy L Thompson   va_list args;
20660f9e2d6SJeremy L Thompson   va_start(args, format);
20760f9e2d6SJeremy L Thompson   fflush(stdout);
2083f21f6b1SJeremy L Thompson   if (color != CEED_DEBUG_COLOR_NONE)
20960f9e2d6SJeremy L Thompson     fprintf(stdout, "\033[38;5;%dm", color);
21060f9e2d6SJeremy L Thompson   vfprintf(stdout, format, args);
2113f21f6b1SJeremy L Thompson   if (color != CEED_DEBUG_COLOR_NONE)
21260f9e2d6SJeremy L Thompson     fprintf(stdout, "\033[m");
21360f9e2d6SJeremy L Thompson   fprintf(stdout, "\n");
21460f9e2d6SJeremy L Thompson   fflush(stdout);
21560f9e2d6SJeremy L Thompson   va_end(args);
21660f9e2d6SJeremy L Thompson }
217fc6bbcedSJeremy L Thompson // LCOV_EXCL_STOP
21860f9e2d6SJeremy L Thompson 
21960f9e2d6SJeremy L Thompson /**
220b11c1e72Sjeremylt   @brief Allocate an array on the host; use CeedMalloc()
221b11c1e72Sjeremylt 
222b11c1e72Sjeremylt   Memory usage can be tracked by the library.  This ensures sufficient
223b11c1e72Sjeremylt     alignment for vectorization and should be used for large allocations.
224b11c1e72Sjeremylt 
225b11c1e72Sjeremylt   @param n     Number of units to allocate
226b11c1e72Sjeremylt   @param unit  Size of each unit
227b11c1e72Sjeremylt   @param p     Address of pointer to hold the result.
228b11c1e72Sjeremylt 
229b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
230b11c1e72Sjeremylt 
231b11c1e72Sjeremylt   @sa CeedFree()
232dfdf5a53Sjeremylt 
2337a982d89SJeremy L. Thompson   @ref Backend
234b11c1e72Sjeremylt **/
235d7b241e6Sjeremylt int CeedMallocArray(size_t n, size_t unit, void *p) {
236d7b241e6Sjeremylt   int ierr = posix_memalign((void **)p, CEED_ALIGN, n*unit);
237d7b241e6Sjeremylt   if (ierr)
238c042f62fSJeremy L Thompson     // LCOV_EXCL_START
239e15f9bd0SJeremy L Thompson     return CeedError(NULL, CEED_ERROR_MAJOR,
240e15f9bd0SJeremy L Thompson                      "posix_memalign failed to allocate %zd "
2411d102b48SJeremy L Thompson                      "members of size %zd\n", n, unit);
242c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
243e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
244d7b241e6Sjeremylt }
245d7b241e6Sjeremylt 
246b11c1e72Sjeremylt /**
247b11c1e72Sjeremylt   @brief Allocate a cleared (zeroed) array on the host; use CeedCalloc()
248b11c1e72Sjeremylt 
249b11c1e72Sjeremylt   Memory usage can be tracked by the library.
250b11c1e72Sjeremylt 
251b11c1e72Sjeremylt   @param n     Number of units to allocate
252b11c1e72Sjeremylt   @param unit  Size of each unit
253b11c1e72Sjeremylt   @param p     Address of pointer to hold the result.
254b11c1e72Sjeremylt 
255b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
256b11c1e72Sjeremylt 
257b11c1e72Sjeremylt   @sa CeedFree()
258dfdf5a53Sjeremylt 
2597a982d89SJeremy L. Thompson   @ref Backend
260b11c1e72Sjeremylt **/
261d7b241e6Sjeremylt int CeedCallocArray(size_t n, size_t unit, void *p) {
262d7b241e6Sjeremylt   *(void **)p = calloc(n, unit);
263d7b241e6Sjeremylt   if (n && unit && !*(void **)p)
264c042f62fSJeremy L Thompson     // LCOV_EXCL_START
265e15f9bd0SJeremy L Thompson     return CeedError(NULL, CEED_ERROR_MAJOR,
266e15f9bd0SJeremy L Thompson                      "calloc failed to allocate %zd members of size "
2671d102b48SJeremy L Thompson                      "%zd\n", n, unit);
268c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
269e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
270d7b241e6Sjeremylt }
271d7b241e6Sjeremylt 
272b11c1e72Sjeremylt /**
273b11c1e72Sjeremylt   @brief Reallocate an array on the host; use CeedRealloc()
274b11c1e72Sjeremylt 
275b11c1e72Sjeremylt   Memory usage can be tracked by the library.
276b11c1e72Sjeremylt 
277b11c1e72Sjeremylt   @param n     Number of units to allocate
278b11c1e72Sjeremylt   @param unit  Size of each unit
279b11c1e72Sjeremylt   @param p     Address of pointer to hold the result.
280b11c1e72Sjeremylt 
281b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
282b11c1e72Sjeremylt 
283b11c1e72Sjeremylt   @sa CeedFree()
284dfdf5a53Sjeremylt 
2857a982d89SJeremy L. Thompson   @ref Backend
286b11c1e72Sjeremylt **/
287d7b241e6Sjeremylt int CeedReallocArray(size_t n, size_t unit, void *p) {
288d7b241e6Sjeremylt   *(void **)p = realloc(*(void **)p, n*unit);
289d7b241e6Sjeremylt   if (n && unit && !*(void **)p)
290c042f62fSJeremy L Thompson     // LCOV_EXCL_START
291e15f9bd0SJeremy L Thompson     return CeedError(NULL, CEED_ERROR_MAJOR,
292e15f9bd0SJeremy L Thompson                      "realloc failed to allocate %zd members of size "
2931d102b48SJeremy L Thompson                      "%zd\n", n, unit);
294c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
295e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
296d7b241e6Sjeremylt }
297d7b241e6Sjeremylt 
29834138859Sjeremylt /** Free memory allocated using CeedMalloc() or CeedCalloc()
29934138859Sjeremylt 
30034138859Sjeremylt   @param p  address of pointer to memory.  This argument is of type void* to
30134138859Sjeremylt               avoid needing a cast, but is the address of the pointer (which is
30234138859Sjeremylt               zeroed) rather than the pointer.
30334138859Sjeremylt **/
304d7b241e6Sjeremylt int CeedFree(void *p) {
305d7b241e6Sjeremylt   free(*(void **)p);
306d7b241e6Sjeremylt   *(void **)p = NULL;
307e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
308d7b241e6Sjeremylt }
309d7b241e6Sjeremylt 
310d7b241e6Sjeremylt /**
3117a982d89SJeremy L. Thompson   @brief Register a Ceed backend
312d7b241e6Sjeremylt 
3137a982d89SJeremy L. Thompson   @param prefix    Prefix of resources for this backend to respond to.  For
3147a982d89SJeremy L. Thompson                      example, the reference backend responds to "/cpu/self".
3157a982d89SJeremy L. Thompson   @param init      Initialization function called by CeedInit() when the backend
3167a982d89SJeremy L. Thompson                      is selected to drive the requested resource.
3177a982d89SJeremy L. Thompson   @param priority  Integer priority.  Lower values are preferred in case the
3187a982d89SJeremy L. Thompson                      resource requested by CeedInit() has non-unique best prefix
3197a982d89SJeremy L. Thompson                      match.
320b11c1e72Sjeremylt 
321b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
322dfdf5a53Sjeremylt 
3237a982d89SJeremy L. Thompson   @ref Backend
324b11c1e72Sjeremylt **/
3257a982d89SJeremy L. Thompson int CeedRegister(const char *prefix, int (*init)(const char *, Ceed),
3267a982d89SJeremy L. Thompson                  unsigned int priority) {
32710243053SJeremy L Thompson   CeedDebugEnv("Backend Register: %s", prefix);
3286a406739SJeremy L Thompson   CeedRegisterImpl(prefix, init, priority);
329e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
330d7b241e6Sjeremylt }
331d7b241e6Sjeremylt 
332b11c1e72Sjeremylt /**
33360f9e2d6SJeremy L Thompson   @brief Return debugging status flag
33460f9e2d6SJeremy L Thompson 
33560f9e2d6SJeremy L Thompson   @param ceed      Ceed context to get debugging flag
336d1d35e2fSjeremylt   @param is_debug  Variable to store debugging flag
33760f9e2d6SJeremy L Thompson 
33860f9e2d6SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
33960f9e2d6SJeremy L Thompson 
340d1d35e2fSjeremylt   @ref Backend
34160f9e2d6SJeremy L Thompson **/
342d1d35e2fSjeremylt int CeedIsDebug(Ceed ceed, bool *is_debug) {
3433f21f6b1SJeremy L Thompson   *is_debug = ceed->is_debug;
344e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
34560f9e2d6SJeremy L Thompson }
34660f9e2d6SJeremy L Thompson 
34760f9e2d6SJeremy L Thompson /**
3487a982d89SJeremy L. Thompson   @brief Retrieve a parent Ceed context
3497a982d89SJeremy L. Thompson 
3507a982d89SJeremy L. Thompson   @param ceed         Ceed context to retrieve parent of
3517a982d89SJeremy L. Thompson   @param[out] parent  Address to save the parent to
3527a982d89SJeremy L. Thompson 
3537a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3547a982d89SJeremy L. Thompson 
3557a982d89SJeremy L. Thompson   @ref Backend
3567a982d89SJeremy L. Thompson **/
3577a982d89SJeremy L. Thompson int CeedGetParent(Ceed ceed, Ceed *parent) {
3587a982d89SJeremy L. Thompson   int ierr;
3597a982d89SJeremy L. Thompson   if (ceed->parent) {
3607a982d89SJeremy L. Thompson     ierr = CeedGetParent(ceed->parent, parent); CeedChk(ierr);
361e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
3627a982d89SJeremy L. Thompson   }
3637a982d89SJeremy L. Thompson   *parent = ceed;
364e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3657a982d89SJeremy L. Thompson }
3667a982d89SJeremy L. Thompson 
3677a982d89SJeremy L. Thompson /**
3687a982d89SJeremy L. Thompson   @brief Retrieve a delegate Ceed context
3697a982d89SJeremy L. Thompson 
3707a982d89SJeremy L. Thompson   @param ceed           Ceed context to retrieve delegate of
3717a982d89SJeremy L. Thompson   @param[out] delegate  Address to save the delegate to
3727a982d89SJeremy L. Thompson 
3737a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3747a982d89SJeremy L. Thompson 
3757a982d89SJeremy L. Thompson   @ref Backend
3767a982d89SJeremy L. Thompson **/
3777a982d89SJeremy L. Thompson int CeedGetDelegate(Ceed ceed, Ceed *delegate) {
3787a982d89SJeremy L. Thompson   *delegate = ceed->delegate;
379e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3807a982d89SJeremy L. Thompson }
3817a982d89SJeremy L. Thompson 
3827a982d89SJeremy L. Thompson /**
3837a982d89SJeremy L. Thompson   @brief Set a delegate Ceed context
3847a982d89SJeremy L. Thompson 
3857a982d89SJeremy L. Thompson   This function allows a Ceed context to set a delegate Ceed context. All
3867a982d89SJeremy L. Thompson     backend implementations default to the delegate Ceed context, unless
3877a982d89SJeremy L. Thompson     overridden.
3887a982d89SJeremy L. Thompson 
3897a982d89SJeremy L. Thompson   @param ceed           Ceed context to set delegate of
3907a982d89SJeremy L. Thompson   @param[out] delegate  Address to set the delegate to
3917a982d89SJeremy L. Thompson 
3927a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3937a982d89SJeremy L. Thompson 
3947a982d89SJeremy L. Thompson   @ref Backend
3957a982d89SJeremy L. Thompson **/
3967a982d89SJeremy L. Thompson int CeedSetDelegate(Ceed ceed, Ceed delegate) {
3977a982d89SJeremy L. Thompson   ceed->delegate = delegate;
3987a982d89SJeremy L. Thompson   delegate->parent = ceed;
399e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4007a982d89SJeremy L. Thompson }
4017a982d89SJeremy L. Thompson 
4027a982d89SJeremy L. Thompson /**
4037a982d89SJeremy L. Thompson   @brief Retrieve a delegate Ceed context for a specific object type
4047a982d89SJeremy L. Thompson 
4057a982d89SJeremy L. Thompson   @param ceed           Ceed context to retrieve delegate of
4067a982d89SJeremy L. Thompson   @param[out] delegate  Address to save the delegate to
407d1d35e2fSjeremylt   @param[in] obj_name   Name of the object type to retrieve delegate for
4087a982d89SJeremy L. Thompson 
4097a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4107a982d89SJeremy L. Thompson 
4117a982d89SJeremy L. Thompson   @ref Backend
4127a982d89SJeremy L. Thompson **/
413d1d35e2fSjeremylt int CeedGetObjectDelegate(Ceed ceed, Ceed *delegate, const char *obj_name) {
4147a982d89SJeremy L. Thompson   CeedInt ierr;
4157a982d89SJeremy L. Thompson 
4167a982d89SJeremy L. Thompson   // Check for object delegate
417d1d35e2fSjeremylt   for (CeedInt i=0; i<ceed->obj_delegate_count; i++)
418d1d35e2fSjeremylt     if (!strcmp(obj_name, ceed->obj_delegates->obj_name)) {
419d1d35e2fSjeremylt       *delegate = ceed->obj_delegates->delegate;
420e15f9bd0SJeremy L Thompson       return CEED_ERROR_SUCCESS;
4217a982d89SJeremy L. Thompson     }
4227a982d89SJeremy L. Thompson 
4237a982d89SJeremy L. Thompson   // Use default delegate if no object delegate
4247a982d89SJeremy L. Thompson   ierr = CeedGetDelegate(ceed, delegate); CeedChk(ierr);
425e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4267a982d89SJeremy L. Thompson }
4277a982d89SJeremy L. Thompson 
4287a982d89SJeremy L. Thompson /**
4297a982d89SJeremy L. Thompson   @brief Set a delegate Ceed context for a specific object type
4307a982d89SJeremy L. Thompson 
4317a982d89SJeremy L. Thompson   This function allows a Ceed context to set a delegate Ceed context for a
4327a982d89SJeremy L. Thompson     given type of Ceed object. All backend implementations default to the
4337a982d89SJeremy L. Thompson     delegate Ceed context for this object. For example,
4347a982d89SJeremy L. Thompson     CeedSetObjectDelegate(ceed, refceed, "Basis")
4357a982d89SJeremy L. Thompson   uses refceed implementations for all CeedBasis backend functions.
4367a982d89SJeremy L. Thompson 
4377a982d89SJeremy L. Thompson   @param ceed           Ceed context to set delegate of
4387a982d89SJeremy L. Thompson   @param[out] delegate  Address to set the delegate to
439d1d35e2fSjeremylt   @param[in] obj_name   Name of the object type to set delegate for
4407a982d89SJeremy L. Thompson 
4417a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4427a982d89SJeremy L. Thompson 
4437a982d89SJeremy L. Thompson   @ref Backend
4447a982d89SJeremy L. Thompson **/
445d1d35e2fSjeremylt int CeedSetObjectDelegate(Ceed ceed, Ceed delegate, const char *obj_name) {
4467a982d89SJeremy L. Thompson   CeedInt ierr;
447d1d35e2fSjeremylt   CeedInt count = ceed->obj_delegate_count;
4487a982d89SJeremy L. Thompson 
4497a982d89SJeremy L. Thompson   // Malloc or Realloc
4507a982d89SJeremy L. Thompson   if (count) {
451d1d35e2fSjeremylt     ierr = CeedRealloc(count+1, &ceed->obj_delegates); CeedChk(ierr);
4527a982d89SJeremy L. Thompson   } else {
453d1d35e2fSjeremylt     ierr = CeedCalloc(1, &ceed->obj_delegates); CeedChk(ierr);
4547a982d89SJeremy L. Thompson   }
455d1d35e2fSjeremylt   ceed->obj_delegate_count++;
4567a982d89SJeremy L. Thompson 
4577a982d89SJeremy L. Thompson   // Set object delegate
458d1d35e2fSjeremylt   ceed->obj_delegates[count].delegate = delegate;
459d1d35e2fSjeremylt   size_t slen = strlen(obj_name) + 1;
460d1d35e2fSjeremylt   ierr = CeedMalloc(slen, &ceed->obj_delegates[count].obj_name); CeedChk(ierr);
461d1d35e2fSjeremylt   memcpy(ceed->obj_delegates[count].obj_name, obj_name, slen);
4627a982d89SJeremy L. Thompson 
4637a982d89SJeremy L. Thompson   // Set delegate parent
4647a982d89SJeremy L. Thompson   delegate->parent = ceed;
465e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4667a982d89SJeremy L. Thompson }
4677a982d89SJeremy L. Thompson 
4687a982d89SJeremy L. Thompson /**
4697a982d89SJeremy L. Thompson   @brief Get the fallback resource for CeedOperators
4707a982d89SJeremy L. Thompson 
4717a982d89SJeremy L. Thompson   @param ceed           Ceed context
4727a982d89SJeremy L. Thompson   @param[out] resource  Variable to store fallback resource
4737a982d89SJeremy L. Thompson 
4747a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4757a982d89SJeremy L. Thompson 
4767a982d89SJeremy L. Thompson   @ref Backend
4777a982d89SJeremy L. Thompson **/
4787a982d89SJeremy L. Thompson 
4797a982d89SJeremy L. Thompson int CeedGetOperatorFallbackResource(Ceed ceed, const char **resource) {
480d1d35e2fSjeremylt   *resource = (const char *)ceed->op_fallback_resource;
481e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4827a982d89SJeremy L. Thompson }
4837a982d89SJeremy L. Thompson 
4847a982d89SJeremy L. Thompson /**
4857a982d89SJeremy L. Thompson   @brief Set the fallback resource for CeedOperators. The current resource, if
4867a982d89SJeremy L. Thompson            any, is freed by calling this function. This string is freed upon the
4877a982d89SJeremy L. Thompson            destruction of the Ceed context.
4887a982d89SJeremy L. Thompson 
4897a982d89SJeremy L. Thompson   @param[out] ceed Ceed context
4907a982d89SJeremy L. Thompson   @param resource  Fallback resource to set
4917a982d89SJeremy L. Thompson 
4927a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4937a982d89SJeremy L. Thompson 
4947a982d89SJeremy L. Thompson   @ref Backend
4957a982d89SJeremy L. Thompson **/
4967a982d89SJeremy L. Thompson 
4977a982d89SJeremy L. Thompson int CeedSetOperatorFallbackResource(Ceed ceed, const char *resource) {
4987a982d89SJeremy L. Thompson   int ierr;
4997a982d89SJeremy L. Thompson 
5007a982d89SJeremy L. Thompson   // Free old
501d1d35e2fSjeremylt   ierr = CeedFree(&ceed->op_fallback_resource); CeedChk(ierr);
5027a982d89SJeremy L. Thompson 
5037a982d89SJeremy L. Thompson   // Set new
5047a982d89SJeremy L. Thompson   size_t len = strlen(resource);
5057a982d89SJeremy L. Thompson   char *tmp;
5067a982d89SJeremy L. Thompson   ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr);
5077a982d89SJeremy L. Thompson   memcpy(tmp, resource, len+1);
508d1d35e2fSjeremylt   ceed->op_fallback_resource = tmp;
509e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5107a982d89SJeremy L. Thompson }
5117a982d89SJeremy L. Thompson 
5127a982d89SJeremy L. Thompson /**
5137a982d89SJeremy L. Thompson   @brief Get the parent Ceed context associated with a fallback Ceed context
5147a982d89SJeremy L. Thompson            for a CeedOperator
5157a982d89SJeremy L. Thompson 
5167a982d89SJeremy L. Thompson   @param ceed         Ceed context
5177a982d89SJeremy L. Thompson   @param[out] parent  Variable to store parent Ceed context
5187a982d89SJeremy L. Thompson 
5197a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5207a982d89SJeremy L. Thompson 
5217a982d89SJeremy L. Thompson   @ref Backend
5227a982d89SJeremy L. Thompson **/
5237a982d89SJeremy L. Thompson 
5247a982d89SJeremy L. Thompson int CeedGetOperatorFallbackParentCeed(Ceed ceed, Ceed *parent) {
525d1d35e2fSjeremylt   *parent = ceed->op_fallback_parent;
526e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5277a982d89SJeremy L. Thompson }
5287a982d89SJeremy L. Thompson 
5297a982d89SJeremy L. Thompson /**
5309525855cSJeremy L Thompson   @brief Flag Ceed context as deterministic
5319525855cSJeremy L Thompson 
5329525855cSJeremy L Thompson   @param ceed                   Ceed to flag as deterministic
53396b902e2Sjeremylt   @param[out] is_deterministic  Deterministic status to set
5349525855cSJeremy L Thompson 
5359525855cSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
5369525855cSJeremy L Thompson 
5379525855cSJeremy L Thompson   @ref Backend
5389525855cSJeremy L Thompson **/
5399525855cSJeremy L Thompson 
540d1d35e2fSjeremylt int CeedSetDeterministic(Ceed ceed, bool is_deterministic) {
541d1d35e2fSjeremylt   ceed->is_deterministic = is_deterministic;
542e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5439525855cSJeremy L Thompson }
5449525855cSJeremy L Thompson 
5459525855cSJeremy L Thompson /**
5467a982d89SJeremy L. Thompson   @brief Set a backend function
5477a982d89SJeremy L. Thompson 
5487a982d89SJeremy L. Thompson   This function is used for a backend to set the function associated with
5497a982d89SJeremy L. Thompson   the Ceed objects. For example,
5507a982d89SJeremy L. Thompson     CeedSetBackendFunction(ceed, "Ceed", ceed, "VectorCreate", BackendVectorCreate)
5517a982d89SJeremy L. Thompson   sets the backend implementation of 'CeedVectorCreate' and
5527a982d89SJeremy L. Thompson     CeedSetBackendFunction(ceed, "Basis", basis, "Apply", BackendBasisApply)
5537a982d89SJeremy L. Thompson   sets the backend implementation of 'CeedBasisApply'. Note, the prefix 'Ceed'
5547a982d89SJeremy L. Thompson   is not required for the object type ("Basis" vs "CeedBasis").
5557a982d89SJeremy L. Thompson 
5567a982d89SJeremy L. Thompson   @param ceed         Ceed context for error handling
5577a982d89SJeremy L. Thompson   @param type         Type of Ceed object to set function for
5587a982d89SJeremy L. Thompson   @param[out] object  Ceed object to set function for
559d1d35e2fSjeremylt   @param func_name    Name of function to set
5607a982d89SJeremy L. Thompson   @param f            Function to set
5617a982d89SJeremy L. Thompson 
5627a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5637a982d89SJeremy L. Thompson 
5647a982d89SJeremy L. Thompson   @ref Backend
5657a982d89SJeremy L. Thompson **/
5667a982d89SJeremy L. Thompson int CeedSetBackendFunction(Ceed ceed, const char *type, void *object,
567d1d35e2fSjeremylt                            const char *func_name, int (*f)()) {
568d1d35e2fSjeremylt   char lookup_name[CEED_MAX_RESOURCE_LEN+1] = "";
5697a982d89SJeremy L. Thompson 
5707a982d89SJeremy L. Thompson   // Build lookup name
5717a982d89SJeremy L. Thompson   if (strcmp(type, "Ceed"))
572d1d35e2fSjeremylt     strncat (lookup_name, "Ceed", CEED_MAX_RESOURCE_LEN);
573d1d35e2fSjeremylt   strncat(lookup_name, type, CEED_MAX_RESOURCE_LEN);
574d1d35e2fSjeremylt   strncat(lookup_name, func_name, CEED_MAX_RESOURCE_LEN);
5757a982d89SJeremy L. Thompson 
5767a982d89SJeremy L. Thompson   // Find and use offset
577d1d35e2fSjeremylt   for (CeedInt i = 0; ceed->f_offsets[i].func_name; i++)
578d1d35e2fSjeremylt     if (!strcmp(ceed->f_offsets[i].func_name, lookup_name)) {
579d1d35e2fSjeremylt       size_t offset = ceed->f_offsets[i].offset;
5807a982d89SJeremy L. Thompson       int (**fpointer)(void) = (int (**)(void))((char *)object + offset); // *NOPAD*
5817a982d89SJeremy L. Thompson       *fpointer = f;
582e15f9bd0SJeremy L Thompson       return CEED_ERROR_SUCCESS;
5837a982d89SJeremy L. Thompson     }
5847a982d89SJeremy L. Thompson 
5857a982d89SJeremy L. Thompson   // LCOV_EXCL_START
586e15f9bd0SJeremy L Thompson   return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
587e15f9bd0SJeremy L Thompson                    "Requested function '%s' was not found for CEED "
588d1d35e2fSjeremylt                    "object '%s'", func_name, type);
5897a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
5907a982d89SJeremy L. Thompson }
5917a982d89SJeremy L. Thompson 
5927a982d89SJeremy L. Thompson /**
5937a982d89SJeremy L. Thompson   @brief Retrieve backend data for a Ceed context
5947a982d89SJeremy L. Thompson 
5957a982d89SJeremy L. Thompson   @param ceed       Ceed context to retrieve data of
5967a982d89SJeremy L. Thompson   @param[out] data  Address to save data to
5977a982d89SJeremy L. Thompson 
5987a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5997a982d89SJeremy L. Thompson 
6007a982d89SJeremy L. Thompson   @ref Backend
6017a982d89SJeremy L. Thompson **/
602777ff853SJeremy L Thompson int CeedGetData(Ceed ceed, void *data) {
603777ff853SJeremy L Thompson   *(void **)data = ceed->data;
604e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6057a982d89SJeremy L. Thompson }
6067a982d89SJeremy L. Thompson 
6077a982d89SJeremy L. Thompson /**
6087a982d89SJeremy L. Thompson   @brief Set backend data for a Ceed context
6097a982d89SJeremy L. Thompson 
6107a982d89SJeremy L. Thompson   @param ceed  Ceed context to set data of
6117a982d89SJeremy L. Thompson   @param data  Address of data to set
6127a982d89SJeremy L. Thompson 
6137a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6147a982d89SJeremy L. Thompson 
6157a982d89SJeremy L. Thompson   @ref Backend
6167a982d89SJeremy L. Thompson **/
617777ff853SJeremy L Thompson int CeedSetData(Ceed ceed, void *data) {
618777ff853SJeremy L Thompson   ceed->data = data;
619e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6207a982d89SJeremy L. Thompson }
6217a982d89SJeremy L. Thompson 
62234359f16Sjeremylt /**
62334359f16Sjeremylt   @brief Increment the reference counter for a Ceed context
62434359f16Sjeremylt 
62534359f16Sjeremylt   @param ceed  Ceed context to increment the reference counter
62634359f16Sjeremylt 
62734359f16Sjeremylt   @return An error code: 0 - success, otherwise - failure
62834359f16Sjeremylt 
62934359f16Sjeremylt   @ref Backend
63034359f16Sjeremylt **/
6319560d06aSjeremylt int CeedReference(Ceed ceed) {
63234359f16Sjeremylt   ceed->ref_count++;
63334359f16Sjeremylt   return CEED_ERROR_SUCCESS;
63434359f16Sjeremylt }
63534359f16Sjeremylt 
6367a982d89SJeremy L. Thompson /// @}
6377a982d89SJeremy L. Thompson 
6387a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
6397a982d89SJeremy L. Thompson /// Ceed Public API
6407a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
6417a982d89SJeremy L. Thompson /// @addtogroup CeedUser
6427a982d89SJeremy L. Thompson /// @{
6437a982d89SJeremy L. Thompson 
6447a982d89SJeremy L. Thompson /**
64592ee7d1cSjeremylt   @brief Get the list of available resource names for Ceed contexts
6469ff86846Sjeremylt   Note: The caller is responsible for `free()`ing the resources and priorities arrays,
6479ff86846Sjeremylt           but should not `free()` the contents of the resources array.
64822e44211Sjeremylt 
64992ee7d1cSjeremylt   @param[out] n           Number of available resources
65092ee7d1cSjeremylt   @param[out] resources   List of available resource names
65122e44211Sjeremylt   @param[out] priorities  Resource name prioritization values, lower is better
65222e44211Sjeremylt 
65322e44211Sjeremylt   @return An error code: 0 - success, otherwise - failure
65422e44211Sjeremylt 
65522e44211Sjeremylt   @ref User
65622e44211Sjeremylt **/
65722e44211Sjeremylt // LCOV_EXCL_START
65822e44211Sjeremylt int CeedRegistryGetList(size_t *n, char ***const resources,
65922e44211Sjeremylt                         CeedInt **priorities) {
660d0c91ce9Sjeremylt   *n = 0;
6619ff86846Sjeremylt   *resources = malloc(num_backends * sizeof(**resources));
6629ff86846Sjeremylt   if (!resources)
6639ff86846Sjeremylt     return CeedError(NULL, CEED_ERROR_MAJOR, "malloc() failure");
6649ff86846Sjeremylt   if (priorities) {
6659ff86846Sjeremylt     *priorities = malloc(num_backends * sizeof(**priorities));
6669ff86846Sjeremylt     if (!priorities)
6679ff86846Sjeremylt       return CeedError(NULL, CEED_ERROR_MAJOR, "malloc() failure");
6689ff86846Sjeremylt   }
66922e44211Sjeremylt   for (size_t i=0; i<num_backends; i++) {
670d0c91ce9Sjeremylt     // Only report compiled backends
671d0c91ce9Sjeremylt     if (backends[i].priority < CEED_MAX_BACKEND_PRIORITY) {
67222e44211Sjeremylt       *resources[i] = backends[i].prefix;
6739ff86846Sjeremylt       if (priorities) *priorities[i] = backends[i].priority;
674d0c91ce9Sjeremylt       *n += 1;
675d0c91ce9Sjeremylt     }
676d0c91ce9Sjeremylt   }
67778464608Sjeremylt   if (*n == 0)
67878464608Sjeremylt     // LCOV_EXCL_START
67978464608Sjeremylt     return CeedError(NULL, CEED_ERROR_MAJOR, "No backends installed");
68078464608Sjeremylt   // LCOV_EXCL_STOP
681d0c91ce9Sjeremylt   *resources = realloc(*resources, *n * sizeof(**resources));
682d0c91ce9Sjeremylt   if (!resources)
683d0c91ce9Sjeremylt     return CeedError(NULL, CEED_ERROR_MAJOR, "realloc() failure");
684d0c91ce9Sjeremylt   if (priorities) {
685d0c91ce9Sjeremylt     *priorities = realloc(*priorities, *n * sizeof(**priorities));
686d0c91ce9Sjeremylt     if (!priorities)
687d0c91ce9Sjeremylt       return CeedError(NULL, CEED_ERROR_MAJOR, "realloc() failure");
68822e44211Sjeremylt   }
68922e44211Sjeremylt   return CEED_ERROR_SUCCESS;
69045f1e315Sjeremylt }
69122e44211Sjeremylt // LCOV_EXCL_STOP
69222e44211Sjeremylt 
69322e44211Sjeremylt /**
694d79b80ecSjeremylt   @brief Initialize a \ref Ceed context to use the specified resource.
69522e44211Sjeremylt   Note: Prefixing the resource with "help:" (e.g. "help:/cpu/self")
69622e44211Sjeremylt     will result in CeedInt printing the current libCEED version number
69792ee7d1cSjeremylt     and a list of current available backend resources to stderr.
698b11c1e72Sjeremylt 
699b11c1e72Sjeremylt   @param resource  Resource to use, e.g., "/cpu/self"
700b11c1e72Sjeremylt   @param ceed      The library context
701b11c1e72Sjeremylt   @sa CeedRegister() CeedDestroy()
702b11c1e72Sjeremylt 
703b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
704dfdf5a53Sjeremylt 
7057a982d89SJeremy L. Thompson   @ref User
706b11c1e72Sjeremylt **/
707d7b241e6Sjeremylt int CeedInit(const char *resource, Ceed *ceed) {
708d7b241e6Sjeremylt   int ierr;
709d0c91ce9Sjeremylt   size_t match_len = 0, match_idx = UINT_MAX,
710d0c91ce9Sjeremylt          match_priority = CEED_MAX_BACKEND_PRIORITY, priority;
711d7b241e6Sjeremylt 
712fe2413ffSjeremylt   // Find matching backend
7131d102b48SJeremy L Thompson   if (!resource)
71413873f79Sjeremylt     // LCOV_EXCL_START
715e15f9bd0SJeremy L Thompson     return CeedError(NULL, CEED_ERROR_MAJOR, "No resource provided");
71613873f79Sjeremylt   // LCOV_EXCL_STOP
7171d013790SJed Brown   ierr = CeedRegisterAll(); CeedChk(ierr);
71813873f79Sjeremylt 
71922e44211Sjeremylt   // Check for help request
72022e44211Sjeremylt   const char *help_prefix = "help";
72122e44211Sjeremylt   size_t match_help;
72222e44211Sjeremylt   for (match_help=0; match_help<4
72322e44211Sjeremylt        && resource[match_help] == help_prefix[match_help]; match_help++) {}
72422e44211Sjeremylt   if (match_help == 4) {
72522e44211Sjeremylt     fprintf(stderr, "libCEED version: %d.%d%d%s\n", CEED_VERSION_MAJOR,
72622e44211Sjeremylt             CEED_VERSION_MINOR, CEED_VERSION_PATCH,
72722e44211Sjeremylt             CEED_VERSION_RELEASE ? "" : "+development");
72892ee7d1cSjeremylt     fprintf(stderr, "Available backend resources:\n");
72922e44211Sjeremylt     for (size_t i=0; i<num_backends; i++) {
730d0c91ce9Sjeremylt       // Only report compiled backends
731d0c91ce9Sjeremylt       if (backends[i].priority < CEED_MAX_BACKEND_PRIORITY)
73222e44211Sjeremylt         fprintf(stderr, "  %s\n", backends[i].prefix);
73322e44211Sjeremylt     }
73422e44211Sjeremylt     fflush(stderr);
73522e44211Sjeremylt     match_help = 5; // Delineating character expected
73622e44211Sjeremylt   } else {
73722e44211Sjeremylt     match_help = 0;
73822e44211Sjeremylt   }
73922e44211Sjeremylt 
7409c9a0587SLeila Ghaffari   // Find best match, computed as number of matching characters
7419c9a0587SLeila Ghaffari   //   from requested resource stem
7422bbc7fe8Sjeremylt   size_t stem_length;
74322e44211Sjeremylt   for (stem_length=0; resource[stem_length+match_help]
74422e44211Sjeremylt        && resource[stem_length+match_help] != ':'; stem_length++) {}
745d7b241e6Sjeremylt   for (size_t i=0; i<num_backends; i++) {
746d7b241e6Sjeremylt     size_t n;
747d7b241e6Sjeremylt     const char *prefix = backends[i].prefix;
74822e44211Sjeremylt     for (n=0; prefix[n] && prefix[n] == resource[n+match_help]; n++) {}
749d7b241e6Sjeremylt     priority = backends[i].priority;
750d1d35e2fSjeremylt     if (n > match_len || (n == match_len && match_priority > priority)) {
751d1d35e2fSjeremylt       match_len = n;
752d1d35e2fSjeremylt       match_priority = priority;
753d1d35e2fSjeremylt       match_idx = i;
754d7b241e6Sjeremylt     }
755d7b241e6Sjeremylt   }
7569c9a0587SLeila Ghaffari   // Using Levenshtein distance to find closest match
7579c9a0587SLeila Ghaffari   if (match_len <= 1 || match_len != stem_length) {
758203015caSLeila Ghaffari     // LCOV_EXCL_START
7599c9a0587SLeila Ghaffari     size_t lev_dis = UINT_MAX;
7609c9a0587SLeila Ghaffari     size_t lev_idx = UINT_MAX, lev_priority = CEED_MAX_BACKEND_PRIORITY;
7619c9a0587SLeila Ghaffari     for (size_t i=0; i<num_backends; i++) {
7629c9a0587SLeila Ghaffari       const char *prefix = backends[i].prefix;
7639c9a0587SLeila Ghaffari       size_t prefix_length = strlen(backends[i].prefix);
7649c9a0587SLeila Ghaffari       size_t min_len = (prefix_length < stem_length) ? prefix_length : stem_length;
765092904ddSLeila Ghaffari       size_t column[min_len+1];
766092904ddSLeila Ghaffari       for (size_t j=0; j<=min_len; j++) column[j] = j;
7679c9a0587SLeila Ghaffari       for (size_t j=1; j<=min_len; j++) {
7689c9a0587SLeila Ghaffari         column[0] = j;
7699c9a0587SLeila Ghaffari         for (size_t k=1, last_diag=j-1; k<=min_len; k++) {
770092904ddSLeila Ghaffari           size_t old_diag = column[k];
7719c9a0587SLeila Ghaffari           size_t min_1 = (column[k] < column[k-1]) ? column[k]+1 : column[k-1]+1;
7729c9a0587SLeila Ghaffari           size_t min_2 = last_diag + (resource[k-1] == prefix[j-1] ? 0 : 1);
7739c9a0587SLeila Ghaffari           column[k] = (min_1 < min_2) ? min_1 : min_2;
7749c9a0587SLeila Ghaffari           last_diag = old_diag;
7759c9a0587SLeila Ghaffari         }
7769c9a0587SLeila Ghaffari       }
7779c9a0587SLeila Ghaffari       size_t n = column[min_len];
7789c9a0587SLeila Ghaffari       priority = backends[i].priority;
7799c9a0587SLeila Ghaffari       if (n < lev_dis || (n == lev_dis
7809c9a0587SLeila Ghaffari                           && lev_priority > priority)) {
7819c9a0587SLeila Ghaffari         lev_dis = n;
7829c9a0587SLeila Ghaffari         lev_priority = priority;
7839c9a0587SLeila Ghaffari         lev_idx = i;
7849c9a0587SLeila Ghaffari       }
7859c9a0587SLeila Ghaffari     }
7869c9a0587SLeila Ghaffari     const char *prefix_lev = backends[lev_idx].prefix;
7879c9a0587SLeila Ghaffari     size_t lev_length;
7889c9a0587SLeila Ghaffari     for (lev_length=0; prefix_lev[lev_length]
7899c9a0587SLeila Ghaffari          && prefix_lev[lev_length] != '\0'; lev_length++) {}
7909c9a0587SLeila Ghaffari     size_t m = (lev_length < stem_length) ? lev_length : stem_length;
7919c9a0587SLeila Ghaffari     if (lev_dis+1 >= m) {
792e15f9bd0SJeremy L Thompson       return CeedError(NULL, CEED_ERROR_MAJOR, "No suitable backend: %s",
793e15f9bd0SJeremy L Thompson                        resource);
7949c9a0587SLeila Ghaffari     } else {
79587250337Sjeremylt       return CeedError(NULL, CEED_ERROR_MAJOR, "No suitable backend: %s\n"
7969c9a0587SLeila Ghaffari                        "Closest match: %s", resource, backends[lev_idx].prefix);
7972bbc7fe8Sjeremylt     }
798203015caSLeila Ghaffari     // LCOV_EXCL_STOP
7999c9a0587SLeila Ghaffari   }
800fe2413ffSjeremylt 
801fe2413ffSjeremylt   // Setup Ceed
802d7b241e6Sjeremylt   ierr = CeedCalloc(1, ceed); CeedChk(ierr);
803bc81ce41Sjeremylt   const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER");
8041d102b48SJeremy L Thompson   if (!ceed_error_handler)
8051d102b48SJeremy L Thompson     ceed_error_handler = "abort";
806bc81ce41Sjeremylt   if (!strcmp(ceed_error_handler, "exit"))
80756e866f4SJed Brown     (*ceed)->Error = CeedErrorExit;
808477729cfSJeremy L Thompson   else if (!strcmp(ceed_error_handler, "store"))
809477729cfSJeremy L Thompson     (*ceed)->Error = CeedErrorStore;
81056e866f4SJed Brown   else
811d7b241e6Sjeremylt     (*ceed)->Error = CeedErrorAbort;
812d1d35e2fSjeremylt   memcpy((*ceed)->err_msg, "No error message stored", 24);
813d1d35e2fSjeremylt   (*ceed)->ref_count = 1;
814d7b241e6Sjeremylt   (*ceed)->data = NULL;
815fe2413ffSjeremylt 
816fe2413ffSjeremylt   // Set lookup table
817d1d35e2fSjeremylt   FOffset f_offsets[] = {
8186e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, Error),
8196e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, GetPreferredMemType),
8206e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, Destroy),
821f8902d9eSjeremylt     CEED_FTABLE_ENTRY(Ceed, VectorCreate),
8226e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreate),
8236e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked),
8246e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1),
8256e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, BasisCreateH1),
8266e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, TensorContractCreate),
8276e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, QFunctionCreate),
828777ff853SJeremy L Thompson     CEED_FTABLE_ENTRY(Ceed, QFunctionContextCreate),
8296e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, OperatorCreate),
8306e79d475Sjeremylt     CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate),
831*9c774eddSJeremy L Thompson     CEED_FTABLE_ENTRY(CeedVector, HasValidArray),
832*9c774eddSJeremy L Thompson     CEED_FTABLE_ENTRY(CeedVector, HasBorrowedArrayOfType),
8336e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, SetArray),
8346a6c615bSJeremy L Thompson     CEED_FTABLE_ENTRY(CeedVector, TakeArray),
8356e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, SetValue),
8366e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, GetArray),
8376e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, GetArrayRead),
838*9c774eddSJeremy L Thompson     CEED_FTABLE_ENTRY(CeedVector, GetArrayWrite),
8396e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, RestoreArray),
8406e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead),
841547d9b97Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, Norm),
842e0dd3b27Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, Scale),
8430f7fd0f8Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, AXPY),
8440f7fd0f8Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, PointwiseMult),
845d99fa3c5SJeremy L Thompson     CEED_FTABLE_ENTRY(CeedVector, Reciprocal),
8466e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedVector, Destroy),
8476e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedElemRestriction, Apply),
8486e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock),
849bd33150aSjeremylt     CEED_FTABLE_ENTRY(CeedElemRestriction, GetOffsets),
8506e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy),
8516e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedBasis, Apply),
8526e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedBasis, Destroy),
8536e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedTensorContract, Apply),
8546e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedTensorContract, Destroy),
8556e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedQFunction, Apply),
8568c84ac63Sjeremylt     CEED_FTABLE_ENTRY(CeedQFunction, SetCUDAUserFunction),
8578c84ac63Sjeremylt     CEED_FTABLE_ENTRY(CeedQFunction, SetHIPUserFunction),
8586e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedQFunction, Destroy),
859*9c774eddSJeremy L Thompson     CEED_FTABLE_ENTRY(CeedQFunctionContext, HasValidData),
860*9c774eddSJeremy L Thompson     CEED_FTABLE_ENTRY(CeedQFunctionContext, HasBorrowedDataOfType),
861777ff853SJeremy L Thompson     CEED_FTABLE_ENTRY(CeedQFunctionContext, SetData),
862891038deSjeremylt     CEED_FTABLE_ENTRY(CeedQFunctionContext, TakeData),
863777ff853SJeremy L Thompson     CEED_FTABLE_ENTRY(CeedQFunctionContext, GetData),
864777ff853SJeremy L Thompson     CEED_FTABLE_ENTRY(CeedQFunctionContext, RestoreData),
865777ff853SJeremy L Thompson     CEED_FTABLE_ENTRY(CeedQFunctionContext, Destroy),
86680ac2e43SJeremy L Thompson     CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunction),
86770a7ffb3SJeremy L Thompson     CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunctionUpdate),
86880ac2e43SJeremy L Thompson     CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleDiagonal),
8699e9210b8SJeremy L Thompson     CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddDiagonal),
87080ac2e43SJeremy L Thompson     CEED_FTABLE_ENTRY(CeedOperator, LinearAssemblePointBlockDiagonal),
8719e9210b8SJeremy L Thompson     CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddPointBlockDiagonal),
872e2f04181SAndrew T. Barker     CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleSymbolic),
873e2f04181SAndrew T. Barker     CEED_FTABLE_ENTRY(CeedOperator, LinearAssemble),
874713f43c3Sjeremylt     CEED_FTABLE_ENTRY(CeedOperator, CreateFDMElementInverse),
8756e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedOperator, Apply),
876250756a7Sjeremylt     CEED_FTABLE_ENTRY(CeedOperator, ApplyComposite),
877cae8b89aSjeremylt     CEED_FTABLE_ENTRY(CeedOperator, ApplyAdd),
878250756a7Sjeremylt     CEED_FTABLE_ENTRY(CeedOperator, ApplyAddComposite),
8796e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian),
8806e79d475Sjeremylt     CEED_FTABLE_ENTRY(CeedOperator, Destroy),
8816e79d475Sjeremylt     {NULL, 0} // End of lookup table - used in SetBackendFunction loop
8821dfeef1dSjeremylt   };
883fe2413ffSjeremylt 
884d1d35e2fSjeremylt   ierr = CeedCalloc(sizeof(f_offsets), &(*ceed)->f_offsets); CeedChk(ierr);
885d1d35e2fSjeremylt   memcpy((*ceed)->f_offsets, f_offsets, sizeof(f_offsets));
886fe2413ffSjeremylt 
8875107b09fSJeremy L Thompson   // Set fallback for advanced CeedOperator functions
888e2f04181SAndrew T. Barker   const char fallbackresource[] = "";
8895107b09fSJeremy L Thompson   ierr = CeedSetOperatorFallbackResource(*ceed, fallbackresource);
8905107b09fSJeremy L Thompson   CeedChk(ierr);
8915107b09fSJeremy L Thompson 
89260f9e2d6SJeremy L Thompson   // Record env variables CEED_DEBUG or DBG
8933f21f6b1SJeremy L Thompson   (*ceed)->is_debug = !!getenv("CEED_DEBUG") || !!getenv("DEBUG") ||
8943f21f6b1SJeremy L Thompson                       !!getenv("DBG");
89560f9e2d6SJeremy L Thompson 
896fe2413ffSjeremylt   // Backend specific setup
897d1d35e2fSjeremylt   ierr = backends[match_idx].init(&resource[match_help], *ceed); CeedChk(ierr);
898fe2413ffSjeremylt 
89922e44211Sjeremylt   // Copy resource prefix, if backend setup successful
900d1d35e2fSjeremylt   size_t len = strlen(backends[match_idx].prefix);
901e07206deSjeremylt   char *tmp;
902e07206deSjeremylt   ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr);
903d1d35e2fSjeremylt   memcpy(tmp, backends[match_idx].prefix, len+1);
904e07206deSjeremylt   (*ceed)->resource = tmp;
905e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
906d7b241e6Sjeremylt }
907d7b241e6Sjeremylt 
908d7b241e6Sjeremylt /**
9099560d06aSjeremylt   @brief Copy the pointer to a Ceed context. Both pointers should
9109560d06aSjeremylt            be destroyed with `CeedDestroy()`;
9119560d06aSjeremylt            Note: If `*ceed_copy` is non-NULL, then it is assumed that
9129560d06aSjeremylt            `*ceed_copy` is a pointer to a Ceed context. This Ceed
9139560d06aSjeremylt            context will be destroyed if `*ceed_copy` is the only
9149560d06aSjeremylt            reference to this Ceed context.
9159560d06aSjeremylt 
9169560d06aSjeremylt   @param ceed            Ceed context to copy reference to
9179560d06aSjeremylt   @param[out] ceed_copy  Variable to store copied reference
9189560d06aSjeremylt 
9199560d06aSjeremylt   @return An error code: 0 - success, otherwise - failure
9209560d06aSjeremylt 
9219560d06aSjeremylt   @ref User
9229560d06aSjeremylt **/
9239560d06aSjeremylt int CeedReferenceCopy(Ceed ceed, Ceed *ceed_copy) {
9249560d06aSjeremylt   int ierr;
9259560d06aSjeremylt 
9269560d06aSjeremylt   ierr = CeedReference(ceed); CeedChk(ierr);
9279560d06aSjeremylt   ierr = CeedDestroy(ceed_copy); CeedChk(ierr);
9289560d06aSjeremylt   *ceed_copy = ceed;
9299560d06aSjeremylt   return CEED_ERROR_SUCCESS;
9309560d06aSjeremylt }
9319560d06aSjeremylt 
9329560d06aSjeremylt /**
9337a982d89SJeremy L. Thompson   @brief Get the full resource name for a Ceed context
9342f86a920SJeremy L Thompson 
9357a982d89SJeremy L. Thompson   @param ceed           Ceed context to get resource name of
9367a982d89SJeremy L. Thompson   @param[out] resource  Variable to store resource name
9372f86a920SJeremy L Thompson 
9382f86a920SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
9392f86a920SJeremy L Thompson 
9407a982d89SJeremy L. Thompson   @ref User
9415107b09fSJeremy L Thompson **/
9427a982d89SJeremy L. Thompson int CeedGetResource(Ceed ceed, const char **resource) {
9437a982d89SJeremy L. Thompson   *resource = (const char *)ceed->resource;
944e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
9455107b09fSJeremy L Thompson }
9465107b09fSJeremy L Thompson 
9475107b09fSJeremy L Thompson /**
948d79b80ecSjeremylt   @brief Return Ceed context preferred memory type
949c907536fSjeremylt 
950d79b80ecSjeremylt   @param ceed           Ceed context to get preferred memory type of
951d1d35e2fSjeremylt   @param[out] mem_type  Address to save preferred memory type to
952c907536fSjeremylt 
953c907536fSjeremylt   @return An error code: 0 - success, otherwise - failure
954c907536fSjeremylt 
9557a982d89SJeremy L. Thompson   @ref User
956c907536fSjeremylt **/
957d1d35e2fSjeremylt int CeedGetPreferredMemType(Ceed ceed, CeedMemType *mem_type) {
958c907536fSjeremylt   int ierr;
959c263cd57Sjeremylt 
960c907536fSjeremylt   if (ceed->GetPreferredMemType) {
961d1d35e2fSjeremylt     ierr = ceed->GetPreferredMemType(mem_type); CeedChk(ierr);
962c907536fSjeremylt   } else {
963c263cd57Sjeremylt     Ceed delegate;
964c263cd57Sjeremylt     ierr = CeedGetDelegate(ceed, &delegate); CeedChk(ierr);
965c263cd57Sjeremylt 
966c263cd57Sjeremylt     if (delegate) {
967d1d35e2fSjeremylt       ierr = CeedGetPreferredMemType(delegate, mem_type); CeedChk(ierr);
968c263cd57Sjeremylt     } else {
969d1d35e2fSjeremylt       *mem_type = CEED_MEM_HOST;
970c907536fSjeremylt     }
971c263cd57Sjeremylt   }
972e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
973c907536fSjeremylt }
974c907536fSjeremylt 
975c907536fSjeremylt /**
9769525855cSJeremy L Thompson   @brief Get deterministic status of Ceed
9779525855cSJeremy L Thompson 
9789525855cSJeremy L Thompson   @param[in] ceed               Ceed
979d1d35e2fSjeremylt   @param[out] is_deterministic  Variable to store deterministic status
9809525855cSJeremy L Thompson 
9819525855cSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
9829525855cSJeremy L Thompson 
9839525855cSJeremy L Thompson   @ref User
9849525855cSJeremy L Thompson **/
985d1d35e2fSjeremylt int CeedIsDeterministic(Ceed ceed, bool *is_deterministic) {
986d1d35e2fSjeremylt   *is_deterministic = ceed->is_deterministic;
987e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
9889525855cSJeremy L Thompson }
9899525855cSJeremy L Thompson 
9909525855cSJeremy L Thompson /**
9910a0da059Sjeremylt   @brief View a Ceed
9920a0da059Sjeremylt 
9930a0da059Sjeremylt   @param[in] ceed    Ceed to view
9940a0da059Sjeremylt   @param[in] stream  Filestream to write to
9950a0da059Sjeremylt 
9960a0da059Sjeremylt   @return An error code: 0 - success, otherwise - failure
9970a0da059Sjeremylt 
9980a0da059Sjeremylt   @ref User
9990a0da059Sjeremylt **/
10000a0da059Sjeremylt int CeedView(Ceed ceed, FILE *stream) {
10010a0da059Sjeremylt   int ierr;
1002d1d35e2fSjeremylt   CeedMemType mem_type;
10030a0da059Sjeremylt 
1004d1d35e2fSjeremylt   ierr = CeedGetPreferredMemType(ceed, &mem_type); CeedChk(ierr);
10050a0da059Sjeremylt 
10060a0da059Sjeremylt   fprintf(stream, "Ceed\n"
10070a0da059Sjeremylt           "  Ceed Resource: %s\n"
10080a0da059Sjeremylt           "  Preferred MemType: %s\n",
1009d1d35e2fSjeremylt           ceed->resource, CeedMemTypes[mem_type]);
1010e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
10110a0da059Sjeremylt }
10120a0da059Sjeremylt 
10130a0da059Sjeremylt /**
1014b11c1e72Sjeremylt   @brief Destroy a Ceed context
1015d7b241e6Sjeremylt 
1016d7b241e6Sjeremylt   @param ceed  Address of Ceed context to destroy
1017b11c1e72Sjeremylt 
1018b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1019dfdf5a53Sjeremylt 
10207a982d89SJeremy L. Thompson   @ref User
1021b11c1e72Sjeremylt **/
1022d7b241e6Sjeremylt int CeedDestroy(Ceed *ceed) {
1023d7b241e6Sjeremylt   int ierr;
1024d1d35e2fSjeremylt   if (!*ceed || --(*ceed)->ref_count > 0) return CEED_ERROR_SUCCESS;
10255fe0d4faSjeremylt   if ((*ceed)->delegate) {
10265fe0d4faSjeremylt     ierr = CeedDestroy(&(*ceed)->delegate); CeedChk(ierr);
10275fe0d4faSjeremylt   }
10280ace9bf2Sjeremylt 
1029d1d35e2fSjeremylt   if ((*ceed)->obj_delegate_count > 0) {
1030d1d35e2fSjeremylt     for (int i=0; i<(*ceed)->obj_delegate_count; i++) {
1031d1d35e2fSjeremylt       ierr = CeedDestroy(&((*ceed)->obj_delegates[i].delegate)); CeedChk(ierr);
1032d1d35e2fSjeremylt       ierr = CeedFree(&(*ceed)->obj_delegates[i].obj_name); CeedChk(ierr);
1033aefd8378Sjeremylt     }
1034d1d35e2fSjeremylt     ierr = CeedFree(&(*ceed)->obj_delegates); CeedChk(ierr);
1035aefd8378Sjeremylt   }
10360ace9bf2Sjeremylt 
1037d7b241e6Sjeremylt   if ((*ceed)->Destroy) {
1038d7b241e6Sjeremylt     ierr = (*ceed)->Destroy(*ceed); CeedChk(ierr);
1039d7b241e6Sjeremylt   }
10400ace9bf2Sjeremylt 
1041d1d35e2fSjeremylt   ierr = CeedFree(&(*ceed)->f_offsets); CeedChk(ierr);
1042e07206deSjeremylt   ierr = CeedFree(&(*ceed)->resource); CeedChk(ierr);
1043d1d35e2fSjeremylt   ierr = CeedDestroy(&(*ceed)->op_fallback_ceed); CeedChk(ierr);
1044d1d35e2fSjeremylt   ierr = CeedFree(&(*ceed)->op_fallback_resource); CeedChk(ierr);
1045d7b241e6Sjeremylt   ierr = CeedFree(ceed); CeedChk(ierr);
1046e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1047d7b241e6Sjeremylt }
1048d7b241e6Sjeremylt 
1049f9982c62SWill Pazner // LCOV_EXCL_START
1050f9982c62SWill Pazner const char *CeedErrorFormat(Ceed ceed, const char *format, va_list *args) {
10513f4a9821SAndrew T. Barker   if (ceed->parent)
10523f4a9821SAndrew T. Barker     return CeedErrorFormat(ceed->parent, format, args);
1053d1d35e2fSjeremylt   if (ceed->op_fallback_parent)
1054d1d35e2fSjeremylt     return CeedErrorFormat(ceed->op_fallback_parent, format, args);
105578464608Sjeremylt   // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized
105678464608Sjeremylt   vsnprintf(ceed->err_msg, CEED_MAX_RESOURCE_LEN, format, *args); // NOLINT
1057d1d35e2fSjeremylt   return ceed->err_msg;
1058f9982c62SWill Pazner }
1059f9982c62SWill Pazner // LCOV_EXCL_STOP
1060f9982c62SWill Pazner 
10617a982d89SJeremy L. Thompson /**
10627a982d89SJeremy L. Thompson   @brief Error handling implementation; use \ref CeedError instead.
10637a982d89SJeremy L. Thompson 
10647a982d89SJeremy L. Thompson   @ref Developer
10657a982d89SJeremy L. Thompson **/
10667a982d89SJeremy L. Thompson int CeedErrorImpl(Ceed ceed, const char *filename, int lineno, const char *func,
10677a982d89SJeremy L. Thompson                   int ecode, const char *format, ...) {
10687a982d89SJeremy L. Thompson   va_list args;
1069d1d35e2fSjeremylt   int ret_val;
10707a982d89SJeremy L. Thompson   va_start(args, format);
10717a982d89SJeremy L. Thompson   if (ceed) {
1072d1d35e2fSjeremylt     ret_val = ceed->Error(ceed, filename, lineno, func, ecode, format, &args);
10737a982d89SJeremy L. Thompson   } else {
1074b0d62198Sjeremylt     // LCOV_EXCL_START
1075477729cfSJeremy L Thompson     const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER");
1076477729cfSJeremy L Thompson     if (!ceed_error_handler)
1077477729cfSJeremy L Thompson       ceed_error_handler = "abort";
1078477729cfSJeremy L Thompson     if (!strcmp(ceed_error_handler, "return"))
1079d1d35e2fSjeremylt       ret_val = CeedErrorReturn(ceed, filename, lineno, func, ecode, format, &args);
1080477729cfSJeremy L Thompson     else
1081477729cfSJeremy L Thompson       // This function will not return
1082d1d35e2fSjeremylt       ret_val = CeedErrorAbort(ceed, filename, lineno, func, ecode, format, &args);
10837a982d89SJeremy L. Thompson   }
10847a982d89SJeremy L. Thompson   va_end(args);
1085d1d35e2fSjeremylt   return ret_val;
1086b0d62198Sjeremylt   // LCOV_EXCL_STOP
10877a982d89SJeremy L. Thompson }
10887a982d89SJeremy L. Thompson 
1089477729cfSJeremy L Thompson /**
1090477729cfSJeremy L Thompson   @brief Error handler that returns without printing anything.
1091477729cfSJeremy L Thompson 
1092477729cfSJeremy L Thompson   Pass this to CeedSetErrorHandler() to obtain this error handling behavior.
1093477729cfSJeremy L Thompson 
1094477729cfSJeremy L Thompson   @ref Developer
1095477729cfSJeremy L Thompson **/
1096477729cfSJeremy L Thompson // LCOV_EXCL_START
1097d1d35e2fSjeremylt int CeedErrorReturn(Ceed ceed, const char *filename, int line_no,
1098d1d35e2fSjeremylt                     const char *func, int err_code, const char *format,
1099f9982c62SWill Pazner                     va_list *args) {
1100d1d35e2fSjeremylt   return err_code;
1101477729cfSJeremy L Thompson }
1102477729cfSJeremy L Thompson // LCOV_EXCL_STOP
1103477729cfSJeremy L Thompson 
1104477729cfSJeremy L Thompson /**
1105477729cfSJeremy L Thompson   @brief Error handler that stores the error message for future use and returns
1106477729cfSJeremy L Thompson            the error.
1107477729cfSJeremy L Thompson 
1108477729cfSJeremy L Thompson   Pass this to CeedSetErrorHandler() to obtain this error handling behavior.
1109477729cfSJeremy L Thompson 
1110477729cfSJeremy L Thompson   @ref Developer
1111477729cfSJeremy L Thompson **/
1112477729cfSJeremy L Thompson // LCOV_EXCL_START
1113d1d35e2fSjeremylt int CeedErrorStore(Ceed ceed, const char *filename, int line_no,
1114d1d35e2fSjeremylt                    const char *func, int err_code, const char *format,
1115f9982c62SWill Pazner                    va_list *args) {
1116477729cfSJeremy L Thompson   if (ceed->parent)
1117d1d35e2fSjeremylt     return CeedErrorStore(ceed->parent, filename, line_no, func, err_code, format,
1118187168c7SJeremy L Thompson                           args);
1119d1d35e2fSjeremylt   if (ceed->op_fallback_parent)
1120d1d35e2fSjeremylt     return CeedErrorStore(ceed->op_fallback_parent, filename, line_no, func,
1121d1d35e2fSjeremylt                           err_code, format, args);
1122477729cfSJeremy L Thompson 
1123477729cfSJeremy L Thompson   // Build message
1124477729cfSJeremy L Thompson   CeedInt len;
1125d1d35e2fSjeremylt   len = snprintf(ceed->err_msg, CEED_MAX_RESOURCE_LEN, "%s:%d in %s(): ",
1126d1d35e2fSjeremylt                  filename, line_no, func);
112778464608Sjeremylt   // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized
112878464608Sjeremylt   // *INDENT-OFF*
112978464608Sjeremylt   vsnprintf(ceed->err_msg + len, CEED_MAX_RESOURCE_LEN - len, format, *args); // NOLINT
113078464608Sjeremylt   // *INDENT-ON*
1131d1d35e2fSjeremylt   return err_code;
1132477729cfSJeremy L Thompson }
1133477729cfSJeremy L Thompson // LCOV_EXCL_STOP
1134477729cfSJeremy L Thompson 
1135477729cfSJeremy L Thompson /**
1136477729cfSJeremy L Thompson   @brief Error handler that prints to stderr and aborts
1137477729cfSJeremy L Thompson 
1138477729cfSJeremy L Thompson   Pass this to CeedSetErrorHandler() to obtain this error handling behavior.
1139477729cfSJeremy L Thompson 
1140477729cfSJeremy L Thompson   @ref Developer
1141477729cfSJeremy L Thompson **/
1142477729cfSJeremy L Thompson // LCOV_EXCL_START
1143d1d35e2fSjeremylt int CeedErrorAbort(Ceed ceed, const char *filename, int line_no,
1144d1d35e2fSjeremylt                    const char *func, int err_code, const char *format,
1145f9982c62SWill Pazner                    va_list *args) {
1146d1d35e2fSjeremylt   fprintf(stderr, "%s:%d in %s(): ", filename, line_no, func);
1147f9982c62SWill Pazner   vfprintf(stderr, format, *args);
1148477729cfSJeremy L Thompson   fprintf(stderr, "\n");
1149477729cfSJeremy L Thompson   abort();
1150d1d35e2fSjeremylt   return err_code;
1151477729cfSJeremy L Thompson }
1152477729cfSJeremy L Thompson // LCOV_EXCL_STOP
1153477729cfSJeremy L Thompson 
1154477729cfSJeremy L Thompson /**
1155477729cfSJeremy L Thompson   @brief Error handler that prints to stderr and exits
1156477729cfSJeremy L Thompson 
1157477729cfSJeremy L Thompson   Pass this to CeedSetErrorHandler() to obtain this error handling behavior.
1158477729cfSJeremy L Thompson 
1159477729cfSJeremy L Thompson   In contrast to CeedErrorAbort(), this exits without a signal, so atexit()
1160477729cfSJeremy L Thompson   handlers (e.g., as used by gcov) are run.
1161477729cfSJeremy L Thompson 
1162477729cfSJeremy L Thompson   @ref Developer
1163477729cfSJeremy L Thompson **/
1164d1d35e2fSjeremylt int CeedErrorExit(Ceed ceed, const char *filename, int line_no,
1165d1d35e2fSjeremylt                   const char *func, int err_code, const char *format, va_list *args) {
1166d1d35e2fSjeremylt   fprintf(stderr, "%s:%d in %s(): ", filename, line_no, func);
116778464608Sjeremylt   // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized
116878464608Sjeremylt   vfprintf(stderr, format, *args); // NOLINT
1169477729cfSJeremy L Thompson   fprintf(stderr, "\n");
1170d1d35e2fSjeremylt   exit(err_code);
1171d1d35e2fSjeremylt   return err_code;
1172477729cfSJeremy L Thompson }
1173477729cfSJeremy L Thompson 
1174477729cfSJeremy L Thompson /**
1175477729cfSJeremy L Thompson   @brief Set error handler
1176477729cfSJeremy L Thompson 
1177477729cfSJeremy L Thompson   A default error handler is set in CeedInit().  Use this function to change
1178477729cfSJeremy L Thompson   the error handler to CeedErrorReturn(), CeedErrorAbort(), or a user-defined
1179477729cfSJeremy L Thompson   error handler.
1180477729cfSJeremy L Thompson 
1181477729cfSJeremy L Thompson   @ref Developer
1182477729cfSJeremy L Thompson **/
1183d1d35e2fSjeremylt int CeedSetErrorHandler(Ceed ceed, CeedErrorHandler handler) {
1184d1d35e2fSjeremylt   ceed->Error = handler;
1185d1d35e2fSjeremylt   if (ceed->delegate) CeedSetErrorHandler(ceed->delegate, handler);
1186d1d35e2fSjeremylt   for (int i=0; i<ceed->obj_delegate_count; i++)
1187d1d35e2fSjeremylt     CeedSetErrorHandler(ceed->obj_delegates[i].delegate, handler);
1188e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1189477729cfSJeremy L Thompson }
1190477729cfSJeremy L Thompson 
1191477729cfSJeremy L Thompson /**
1192477729cfSJeremy L Thompson   @brief Get error message
1193477729cfSJeremy L Thompson 
1194477729cfSJeremy L Thompson   The error message is only stored when using the error handler
1195477729cfSJeremy L Thompson     CeedErrorStore()
1196477729cfSJeremy L Thompson 
1197477729cfSJeremy L Thompson   @param[in] ceed      Ceed contex to retrieve error message
1198d1d35e2fSjeremylt   @param[out] err_msg  Char pointer to hold error message
1199477729cfSJeremy L Thompson 
1200477729cfSJeremy L Thompson   @ref Developer
1201477729cfSJeremy L Thompson **/
1202d1d35e2fSjeremylt int CeedGetErrorMessage(Ceed ceed, const char **err_msg) {
12033f4a9821SAndrew T. Barker   if (ceed->parent)
1204d1d35e2fSjeremylt     return CeedGetErrorMessage(ceed->parent, err_msg);
1205d1d35e2fSjeremylt   if (ceed->op_fallback_parent)
1206d1d35e2fSjeremylt     return CeedGetErrorMessage(ceed->op_fallback_parent, err_msg);
1207d1d35e2fSjeremylt   *err_msg = ceed->err_msg;
1208e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1209477729cfSJeremy L Thompson }
1210477729cfSJeremy L Thompson 
1211477729cfSJeremy L Thompson /**
1212477729cfSJeremy L Thompson   @brief Restore error message
1213477729cfSJeremy L Thompson 
1214477729cfSJeremy L Thompson   The error message is only stored when using the error handler
1215477729cfSJeremy L Thompson     CeedErrorStore()
1216477729cfSJeremy L Thompson 
1217477729cfSJeremy L Thompson   @param[in] ceed      Ceed contex to restore error message
1218d1d35e2fSjeremylt   @param[out] err_msg  Char pointer that holds error message
1219477729cfSJeremy L Thompson 
1220477729cfSJeremy L Thompson   @ref Developer
1221477729cfSJeremy L Thompson **/
1222d1d35e2fSjeremylt int CeedResetErrorMessage(Ceed ceed, const char **err_msg) {
12233f4a9821SAndrew T. Barker   if (ceed->parent)
1224d1d35e2fSjeremylt     return CeedResetErrorMessage(ceed->parent, err_msg);
1225d1d35e2fSjeremylt   if (ceed->op_fallback_parent)
1226d1d35e2fSjeremylt     return CeedResetErrorMessage(ceed->op_fallback_parent, err_msg);
1227d1d35e2fSjeremylt   *err_msg = NULL;
1228d1d35e2fSjeremylt   memcpy(ceed->err_msg, "No error message stored", 24);
1229e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1230477729cfSJeremy L Thompson }
1231477729cfSJeremy L Thompson 
12321070991dSJed Brown /**
12331070991dSJed Brown   @brief Get libCEED library version info
12341070991dSJed Brown 
12351070991dSJed Brown   libCEED version numbers have the form major.minor.patch. Non-release versions
12361070991dSJed Brown   may contain unstable interfaces.
12371070991dSJed Brown 
12381070991dSJed Brown   @param[out] major    Major version of the library
12391070991dSJed Brown   @param[out] minor    Minor version of the library
12401070991dSJed Brown   @param[out] patch    Patch (subminor) version of the library
12411070991dSJed Brown   @param[out] release  True for releases; false for development branches.
12421070991dSJed Brown 
12431070991dSJed Brown   The caller may pass NULL for any arguments that are not needed.
12441070991dSJed Brown 
12451070991dSJed Brown   @sa CEED_VERSION_GE()
12461070991dSJed Brown 
12471070991dSJed Brown   @ref Developer
12481070991dSJed Brown */
12491070991dSJed Brown int CeedGetVersion(int *major, int *minor, int *patch, bool *release) {
12501070991dSJed Brown   if (major) *major = CEED_VERSION_MAJOR;
12511070991dSJed Brown   if (minor) *minor = CEED_VERSION_MINOR;
12521070991dSJed Brown   if (patch) *patch = CEED_VERSION_PATCH;
12531070991dSJed Brown   if (release) *release = CEED_VERSION_RELEASE;
12541070991dSJed Brown   return 0;
12551070991dSJed Brown }
12561070991dSJed Brown 
125780a9ef05SNatalie Beams int CeedGetScalarType(CeedScalarType *scalar_type) {
125880a9ef05SNatalie Beams   *scalar_type = CEED_SCALAR_TYPE;
125980a9ef05SNatalie Beams   return 0;
126080a9ef05SNatalie Beams }
126180a9ef05SNatalie Beams 
126280a9ef05SNatalie Beams 
1263d7b241e6Sjeremylt /// @}
1264