xref: /libCEED/rust/libceed-sys/c-src/interface/ceed.c (revision 4385fb7f4421da9c7ce289d92dc27dadf16843ac)
13d8e8822SJeremy L Thompson // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors.
23d8e8822SJeremy L Thompson // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
3d7b241e6Sjeremylt //
43d8e8822SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause
5d7b241e6Sjeremylt //
63d8e8822SJeremy L Thompson // This file is part of CEED:  http://github.com/ceed
7d7b241e6Sjeremylt 
8d7b241e6Sjeremylt #define _POSIX_C_SOURCE 200112
93d576824SJeremy L Thompson #include <ceed-impl.h>
1049aac155SJeremy L Thompson #include <ceed.h>
112b730f8bSJeremy L Thompson #include <ceed/backend.h>
12aedaa0e5Sjeremylt #include <limits.h>
13d7b241e6Sjeremylt #include <stdarg.h>
1449aac155SJeremy L Thompson #include <stdbool.h>
156e79d475Sjeremylt #include <stddef.h>
16d7b241e6Sjeremylt #include <stdio.h>
17d7b241e6Sjeremylt #include <stdlib.h>
18d7b241e6Sjeremylt #include <string.h>
19d7b241e6Sjeremylt 
20d7b241e6Sjeremylt /// @cond DOXYGEN_SKIP
21d7b241e6Sjeremylt static CeedRequest ceed_request_immediate;
22d7b241e6Sjeremylt static CeedRequest ceed_request_ordered;
23d7b241e6Sjeremylt 
24d7b241e6Sjeremylt static struct {
25d7b241e6Sjeremylt   char prefix[CEED_MAX_RESOURCE_LEN];
26d7b241e6Sjeremylt   int (*init)(const char *resource, Ceed f);
27d7b241e6Sjeremylt   unsigned int priority;
28d7b241e6Sjeremylt } backends[32];
29d7b241e6Sjeremylt static size_t num_backends;
30fe2413ffSjeremylt 
316e79d475Sjeremylt #define CEED_FTABLE_ENTRY(class, method)                     \
32b559d91bSJed Brown   {                                                          \
33b559d91bSJed Brown #class #method, offsetof(struct class##_private, method) \
34b559d91bSJed Brown   }
35d7b241e6Sjeremylt /// @endcond
36d7b241e6Sjeremylt 
37d7b241e6Sjeremylt /// @file
38d7b241e6Sjeremylt /// Implementation of core components of Ceed library
397a982d89SJeremy L. Thompson 
407a982d89SJeremy L. Thompson /// @addtogroup CeedUser
41d7b241e6Sjeremylt /// @{
42d7b241e6Sjeremylt 
43dfdf5a53Sjeremylt /**
44dfdf5a53Sjeremylt   @brief Request immediate completion
45dfdf5a53Sjeremylt 
46ea61e9acSJeremy L Thompson   This predefined constant is passed as the \ref CeedRequest argument to interfaces when the caller wishes for the operation to be performed
47dfdf5a53Sjeremylt immediately. The code
48dfdf5a53Sjeremylt 
49dfdf5a53Sjeremylt   @code
50dfdf5a53Sjeremylt     CeedOperatorApply(op, ..., CEED_REQUEST_IMMEDIATE);
51dfdf5a53Sjeremylt   @endcode
52dfdf5a53Sjeremylt 
53dfdf5a53Sjeremylt   is semantically equivalent to
54dfdf5a53Sjeremylt 
55dfdf5a53Sjeremylt   @code
56dfdf5a53Sjeremylt     CeedRequest request;
57dfdf5a53Sjeremylt     CeedOperatorApply(op, ..., &request);
58dfdf5a53Sjeremylt     CeedRequestWait(&request);
59dfdf5a53Sjeremylt   @endcode
60dfdf5a53Sjeremylt 
61dfdf5a53Sjeremylt   @sa CEED_REQUEST_ORDERED
62dfdf5a53Sjeremylt **/
63d7b241e6Sjeremylt CeedRequest *const CEED_REQUEST_IMMEDIATE = &ceed_request_immediate;
64d7b241e6Sjeremylt 
65d7b241e6Sjeremylt /**
66b11c1e72Sjeremylt   @brief Request ordered completion
67d7b241e6Sjeremylt 
68ea61e9acSJeremy L Thompson   This predefined constant is passed as the \ref CeedRequest argument to interfaces when the caller wishes for the operation to be completed in the
69ea61e9acSJeremy L Thompson   order that it is submitted to the device. It is typically used in a construct such as
70d7b241e6Sjeremylt 
71d7b241e6Sjeremylt   @code
72d7b241e6Sjeremylt     CeedRequest request;
73d7b241e6Sjeremylt     CeedOperatorApply(op1, ..., CEED_REQUEST_ORDERED);
74d7b241e6Sjeremylt     CeedOperatorApply(op2, ..., &request);
75d7b241e6Sjeremylt     // other optional work
768b2d6f4aSMatthew Knepley     CeedRequestWait(&request);
77d7b241e6Sjeremylt   @endcode
78d7b241e6Sjeremylt 
79ea61e9acSJeremy L Thompson   which allows the sequence to complete asynchronously but does not start `op2` until `op1` has completed.
80d7b241e6Sjeremylt 
81ea61e9acSJeremy L Thompson   @todo The current implementation is overly strict, offering equivalent semantics to @ref CEED_REQUEST_IMMEDIATE.
82d7b241e6Sjeremylt 
83d7b241e6Sjeremylt   @sa CEED_REQUEST_IMMEDIATE
84d7b241e6Sjeremylt  */
85d7b241e6Sjeremylt CeedRequest *const CEED_REQUEST_ORDERED = &ceed_request_ordered;
86d7b241e6Sjeremylt 
87b11c1e72Sjeremylt /**
887a982d89SJeremy L. Thompson   @brief Wait for a CeedRequest to complete.
89dfdf5a53Sjeremylt 
907a982d89SJeremy L. Thompson   Calling CeedRequestWait on a NULL request is a no-op.
917a982d89SJeremy L. Thompson 
927a982d89SJeremy L. Thompson   @param req Address of CeedRequest to wait for; zeroed on completion.
937a982d89SJeremy L. Thompson 
947a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
957a982d89SJeremy L. Thompson 
967a982d89SJeremy L. Thompson   @ref User
97b11c1e72Sjeremylt **/
987a982d89SJeremy L. Thompson int CeedRequestWait(CeedRequest *req) {
992b730f8bSJeremy L Thompson   if (!*req) return CEED_ERROR_SUCCESS;
1002b730f8bSJeremy L Thompson   return CeedError(NULL, CEED_ERROR_UNSUPPORTED, "CeedRequestWait not implemented");
101683faae0SJed Brown }
1027a982d89SJeremy L. Thompson 
1037a982d89SJeremy L. Thompson /// @}
1047a982d89SJeremy L. Thompson 
1057a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
1067a982d89SJeremy L. Thompson /// Ceed Library Internal Functions
1077a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
1087a982d89SJeremy L. Thompson /// @addtogroup CeedDeveloper
1097a982d89SJeremy L. Thompson /// @{
110d7b241e6Sjeremylt 
1116a406739SJeremy L Thompson /**
1126a406739SJeremy L Thompson   @brief Register a Ceed backend internally.
113*4385fb7fSSebastian Grimberg 
1146a406739SJeremy L Thompson   Note: Backends should call `CeedRegister` instead.
1156a406739SJeremy L Thompson 
116ea61e9acSJeremy L Thompson   @param[in] prefix    Prefix of resources for this backend to respond to.
117ea61e9acSJeremy L Thompson                          For example, the reference backend responds to "/cpu/self".
118ea61e9acSJeremy L Thompson   @param[in] init      Initialization function called by CeedInit() when the backend is selected to drive the requested resource.
119ea61e9acSJeremy L Thompson   @param[in] priority  Integer priority.
120ea61e9acSJeremy L Thompson                          Lower values are preferred in case the resource requested by CeedInit() has non-unique best prefix match.
1216a406739SJeremy L Thompson 
1226a406739SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1236a406739SJeremy L Thompson 
1246a406739SJeremy L Thompson   @ref Developer
1256a406739SJeremy L Thompson **/
1262b730f8bSJeremy L Thompson int CeedRegisterImpl(const char *prefix, int (*init)(const char *, Ceed), unsigned int priority) {
127ecc88aebSJeremy L Thompson   if (num_backends >= sizeof(backends) / sizeof(backends[0])) {
1286a406739SJeremy L Thompson     // LCOV_EXCL_START
1296a406739SJeremy L Thompson     return CeedError(NULL, CEED_ERROR_MAJOR, "Too many backends");
1306a406739SJeremy L Thompson     // LCOV_EXCL_STOP
131ecc88aebSJeremy L Thompson   }
1326a406739SJeremy L Thompson 
1336a406739SJeremy L Thompson   strncpy(backends[num_backends].prefix, prefix, CEED_MAX_RESOURCE_LEN);
1346a406739SJeremy L Thompson   backends[num_backends].prefix[CEED_MAX_RESOURCE_LEN - 1] = 0;
1356a406739SJeremy L Thompson   backends[num_backends].init                              = init;
1366a406739SJeremy L Thompson   backends[num_backends].priority                          = priority;
1376a406739SJeremy L Thompson   num_backends++;
1386a406739SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1396a406739SJeremy L Thompson }
1406a406739SJeremy L Thompson 
1417a982d89SJeremy L. Thompson /// @}
142d7b241e6Sjeremylt 
1437a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
1447a982d89SJeremy L. Thompson /// Ceed Backend API
1457a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
1467a982d89SJeremy L. Thompson /// @addtogroup CeedBackend
1477a982d89SJeremy L. Thompson /// @{
148d7b241e6Sjeremylt 
149b11c1e72Sjeremylt /**
1503f21f6b1SJeremy L Thompson   @brief Return value of CEED_DEBUG environment variable
15160f9e2d6SJeremy L Thompson 
152ea61e9acSJeremy L Thompson   @param[in] ceed Ceed context
15360f9e2d6SJeremy L Thompson 
1543f21f6b1SJeremy L Thompson   @return boolean value: true  - debugging mode enabled
1553f21f6b1SJeremy L Thompson                          false - debugging mode disabled
15660f9e2d6SJeremy L Thompson 
15760f9e2d6SJeremy L Thompson   @ref Backend
15860f9e2d6SJeremy L Thompson **/
159fc6bbcedSJeremy L Thompson // LCOV_EXCL_START
1602b730f8bSJeremy L Thompson bool CeedDebugFlag(const Ceed ceed) { return ceed->is_debug; }
161fc6bbcedSJeremy L Thompson // LCOV_EXCL_STOP
16260f9e2d6SJeremy L Thompson 
16360f9e2d6SJeremy L Thompson /**
1643f21f6b1SJeremy L Thompson   @brief Return value of CEED_DEBUG environment variable
16560f9e2d6SJeremy L Thompson 
1663f21f6b1SJeremy L Thompson   @return boolean value: true  - debugging mode enabled
1673f21f6b1SJeremy L Thompson                          false - debugging mode disabled
1683f21f6b1SJeremy L Thompson 
1693f21f6b1SJeremy L Thompson   @ref Backend
1703f21f6b1SJeremy L Thompson **/
1713f21f6b1SJeremy L Thompson // LCOV_EXCL_START
1722b730f8bSJeremy L Thompson bool CeedDebugFlagEnv(void) { return !!getenv("CEED_DEBUG") || !!getenv("DEBUG") || !!getenv("DBG"); }
1733f21f6b1SJeremy L Thompson // LCOV_EXCL_STOP
1743f21f6b1SJeremy L Thompson 
1753f21f6b1SJeremy L Thompson /**
1763f21f6b1SJeremy L Thompson   @brief Print debugging information in color
1773f21f6b1SJeremy L Thompson 
17860f9e2d6SJeremy L Thompson   @param color   Color to print
17960f9e2d6SJeremy L Thompson   @param format  Printing format
18060f9e2d6SJeremy L Thompson 
18160f9e2d6SJeremy L Thompson   @ref Backend
18260f9e2d6SJeremy L Thompson **/
183fc6bbcedSJeremy L Thompson // LCOV_EXCL_START
1843f21f6b1SJeremy L Thompson void CeedDebugImpl256(const unsigned char color, const char *format, ...) {
18560f9e2d6SJeremy L Thompson   va_list args;
18660f9e2d6SJeremy L Thompson   va_start(args, format);
18760f9e2d6SJeremy L Thompson   fflush(stdout);
1882b730f8bSJeremy L Thompson   if (color != CEED_DEBUG_COLOR_NONE) fprintf(stdout, "\033[38;5;%dm", color);
18960f9e2d6SJeremy L Thompson   vfprintf(stdout, format, args);
1902b730f8bSJeremy L Thompson   if (color != CEED_DEBUG_COLOR_NONE) fprintf(stdout, "\033[m");
19160f9e2d6SJeremy L Thompson   fprintf(stdout, "\n");
19260f9e2d6SJeremy L Thompson   fflush(stdout);
19360f9e2d6SJeremy L Thompson   va_end(args);
19460f9e2d6SJeremy L Thompson }
195fc6bbcedSJeremy L Thompson // LCOV_EXCL_STOP
19660f9e2d6SJeremy L Thompson 
19760f9e2d6SJeremy L Thompson /**
198b11c1e72Sjeremylt   @brief Allocate an array on the host; use CeedMalloc()
199b11c1e72Sjeremylt 
200ea61e9acSJeremy L Thompson   Memory usage can be tracked by the library.
201ea61e9acSJeremy L Thompson   This ensures sufficient alignment for vectorization and should be used for large allocations.
202b11c1e72Sjeremylt 
203ea61e9acSJeremy L Thompson   @param[in]  n    Number of units to allocate
204ea61e9acSJeremy L Thompson   @param[in]  unit Size of each unit
205ea61e9acSJeremy L Thompson   @param[out] p    Address of pointer to hold the result.
206b11c1e72Sjeremylt 
207b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
208b11c1e72Sjeremylt 
209b11c1e72Sjeremylt   @sa CeedFree()
210dfdf5a53Sjeremylt 
2117a982d89SJeremy L. Thompson   @ref Backend
212b11c1e72Sjeremylt **/
213d7b241e6Sjeremylt int CeedMallocArray(size_t n, size_t unit, void *p) {
214d7b241e6Sjeremylt   int ierr = posix_memalign((void **)p, CEED_ALIGN, n * unit);
2152b730f8bSJeremy L Thompson   if (ierr) {
216c042f62fSJeremy L Thompson     // LCOV_EXCL_START
2172b730f8bSJeremy L Thompson     return CeedError(NULL, CEED_ERROR_MAJOR, "posix_memalign failed to allocate %zd members of size %zd\n", n, unit);
218c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
2192b730f8bSJeremy L Thompson   }
220e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
221d7b241e6Sjeremylt }
222d7b241e6Sjeremylt 
223b11c1e72Sjeremylt /**
224b11c1e72Sjeremylt   @brief Allocate a cleared (zeroed) array on the host; use CeedCalloc()
225b11c1e72Sjeremylt 
226b11c1e72Sjeremylt   Memory usage can be tracked by the library.
227b11c1e72Sjeremylt 
228ea61e9acSJeremy L Thompson   @param[in]  n    Number of units to allocate
229ea61e9acSJeremy L Thompson   @param[in]  unit Size of each unit
230ea61e9acSJeremy L Thompson   @param[out] p    Address of pointer to hold the result.
231b11c1e72Sjeremylt 
232b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
233b11c1e72Sjeremylt 
234b11c1e72Sjeremylt   @sa CeedFree()
235dfdf5a53Sjeremylt 
2367a982d89SJeremy L. Thompson   @ref Backend
237b11c1e72Sjeremylt **/
238d7b241e6Sjeremylt int CeedCallocArray(size_t n, size_t unit, void *p) {
239d7b241e6Sjeremylt   *(void **)p = calloc(n, unit);
2402b730f8bSJeremy L Thompson   if (n && unit && !*(void **)p) {
241c042f62fSJeremy L Thompson     // LCOV_EXCL_START
2422b730f8bSJeremy L Thompson     return CeedError(NULL, CEED_ERROR_MAJOR, "calloc failed to allocate %zd members of size %zd\n", n, unit);
243c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
2442b730f8bSJeremy L Thompson   }
245e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
246d7b241e6Sjeremylt }
247d7b241e6Sjeremylt 
248b11c1e72Sjeremylt /**
249b11c1e72Sjeremylt   @brief Reallocate an array on the host; use CeedRealloc()
250b11c1e72Sjeremylt 
251b11c1e72Sjeremylt   Memory usage can be tracked by the library.
252b11c1e72Sjeremylt 
253ea61e9acSJeremy L Thompson   @param[in]  n    Number of units to allocate
254ea61e9acSJeremy L Thompson   @param[in]  unit Size of each unit
255ea61e9acSJeremy L Thompson   @param[out] p    Address of pointer to hold the result.
256b11c1e72Sjeremylt 
257b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
258b11c1e72Sjeremylt 
259b11c1e72Sjeremylt   @sa CeedFree()
260dfdf5a53Sjeremylt 
2617a982d89SJeremy L. Thompson   @ref Backend
262b11c1e72Sjeremylt **/
263d7b241e6Sjeremylt int CeedReallocArray(size_t n, size_t unit, void *p) {
264d7b241e6Sjeremylt   *(void **)p = realloc(*(void **)p, n * unit);
2652b730f8bSJeremy L Thompson   if (n && unit && !*(void **)p) {
266c042f62fSJeremy L Thompson     // LCOV_EXCL_START
2672b730f8bSJeremy L Thompson     return CeedError(NULL, CEED_ERROR_MAJOR, "realloc failed to allocate %zd members of size %zd\n", n, unit);
268c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
2692b730f8bSJeremy L Thompson   }
270e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
271d7b241e6Sjeremylt }
272d7b241e6Sjeremylt 
273f7e22acaSJeremy L Thompson /**
274f7e22acaSJeremy L Thompson   @brief Allocate a cleared string buffer on the host
275f7e22acaSJeremy L Thompson 
276f7e22acaSJeremy L Thompson   Memory usage can be tracked by the library.
277f7e22acaSJeremy L Thompson 
278ea61e9acSJeremy L Thompson   @param[in]  source Pointer to string to be copied
279ea61e9acSJeremy L Thompson   @param[out] copy   Pointer to variable to hold newly allocated string copy
280f7e22acaSJeremy L Thompson 
281f7e22acaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
282f7e22acaSJeremy L Thompson 
283f7e22acaSJeremy L Thompson   @sa CeedFree()
284f7e22acaSJeremy L Thompson 
285f7e22acaSJeremy L Thompson   @ref Backend
286f7e22acaSJeremy L Thompson **/
287f7e22acaSJeremy L Thompson int CeedStringAllocCopy(const char *source, char **copy) {
288f7e22acaSJeremy L Thompson   size_t len = strlen(source);
2892b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(len + 1, copy));
290d602d780SJeremy L Thompson   memcpy(*copy, source, len);
291f7e22acaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
292f7e22acaSJeremy L Thompson }
293f7e22acaSJeremy L Thompson 
29434138859Sjeremylt /** Free memory allocated using CeedMalloc() or CeedCalloc()
29534138859Sjeremylt 
296ea61e9acSJeremy L Thompson   @param[in,out] p  address of pointer to memory.
297ea61e9acSJeremy L Thompson                       This argument is of type void* to avoid needing a cast, but is the address of the pointer (which is zeroed) rather than the
298ea61e9acSJeremy L Thompson pointer.
29934138859Sjeremylt **/
300d7b241e6Sjeremylt int CeedFree(void *p) {
301d7b241e6Sjeremylt   free(*(void **)p);
302d7b241e6Sjeremylt   *(void **)p = NULL;
303e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
304d7b241e6Sjeremylt }
305d7b241e6Sjeremylt 
306d7b241e6Sjeremylt /**
3077a982d89SJeremy L. Thompson   @brief Register a Ceed backend
308d7b241e6Sjeremylt 
309ea61e9acSJeremy L Thompson   @param[in] prefix   Prefix of resources for this backend to respond to.
310ea61e9acSJeremy L Thompson                         For example, the reference backend responds to "/cpu/self".
311ea61e9acSJeremy L Thompson   @param[in] init     Initialization function called by CeedInit() when the backend is selected to drive the requested resource.
312ea61e9acSJeremy L Thompson   @param[in] priority Integer priority.
313ea61e9acSJeremy L Thompson                         Lower values are preferred in case the resource requested by CeedInit() has non-unique best prefix match.
314b11c1e72Sjeremylt 
315b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
316dfdf5a53Sjeremylt 
3177a982d89SJeremy L. Thompson   @ref Backend
318b11c1e72Sjeremylt **/
3192b730f8bSJeremy L Thompson int CeedRegister(const char *prefix, int (*init)(const char *, Ceed), unsigned int priority) {
32010243053SJeremy L Thompson   CeedDebugEnv("Backend Register: %s", prefix);
3216a406739SJeremy L Thompson   CeedRegisterImpl(prefix, init, priority);
322e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
323d7b241e6Sjeremylt }
324d7b241e6Sjeremylt 
325b11c1e72Sjeremylt /**
32660f9e2d6SJeremy L Thompson   @brief Return debugging status flag
32760f9e2d6SJeremy L Thompson 
328ea61e9acSJeremy L Thompson   @param[in]  ceed     Ceed context to get debugging flag
329ea61e9acSJeremy L Thompson   @param[out] is_debug Variable to store debugging flag
33060f9e2d6SJeremy L Thompson 
33160f9e2d6SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
33260f9e2d6SJeremy L Thompson 
333d1d35e2fSjeremylt   @ref Backend
33460f9e2d6SJeremy L Thompson **/
335d1d35e2fSjeremylt int CeedIsDebug(Ceed ceed, bool *is_debug) {
3363f21f6b1SJeremy L Thompson   *is_debug = ceed->is_debug;
337e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
33860f9e2d6SJeremy L Thompson }
33960f9e2d6SJeremy L Thompson 
34060f9e2d6SJeremy L Thompson /**
3417a982d89SJeremy L. Thompson   @brief Retrieve a parent Ceed context
3427a982d89SJeremy L. Thompson 
343ea61e9acSJeremy L Thompson   @param[in]  ceed   Ceed context to retrieve parent of
3447a982d89SJeremy L. Thompson   @param[out] parent Address to save the parent to
3457a982d89SJeremy L. Thompson 
3467a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3477a982d89SJeremy L. Thompson 
3487a982d89SJeremy L. Thompson   @ref Backend
3497a982d89SJeremy L. Thompson **/
3507a982d89SJeremy L. Thompson int CeedGetParent(Ceed ceed, Ceed *parent) {
3517a982d89SJeremy L. Thompson   if (ceed->parent) {
3522b730f8bSJeremy L Thompson     CeedCall(CeedGetParent(ceed->parent, parent));
353e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
3547a982d89SJeremy L. Thompson   }
3557a982d89SJeremy L. Thompson   *parent = ceed;
356e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3577a982d89SJeremy L. Thompson }
3587a982d89SJeremy L. Thompson 
3597a982d89SJeremy L. Thompson /**
3607a982d89SJeremy L. Thompson   @brief Retrieve a delegate Ceed context
3617a982d89SJeremy L. Thompson 
362ea61e9acSJeremy L Thompson   @param[in]  ceed     Ceed context to retrieve delegate of
3637a982d89SJeremy L. Thompson   @param[out] delegate Address to save the delegate to
3647a982d89SJeremy L. Thompson 
3657a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3667a982d89SJeremy L. Thompson 
3677a982d89SJeremy L. Thompson   @ref Backend
3687a982d89SJeremy L. Thompson **/
3697a982d89SJeremy L. Thompson int CeedGetDelegate(Ceed ceed, Ceed *delegate) {
3707a982d89SJeremy L. Thompson   *delegate = ceed->delegate;
371e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3727a982d89SJeremy L. Thompson }
3737a982d89SJeremy L. Thompson 
3747a982d89SJeremy L. Thompson /**
3757a982d89SJeremy L. Thompson   @brief Set a delegate Ceed context
3767a982d89SJeremy L. Thompson 
377ea61e9acSJeremy L Thompson   This function allows a Ceed context to set a delegate Ceed context.
378ea61e9acSJeremy L Thompson     All backend implementations default to the delegate Ceed context, unless overridden.
3797a982d89SJeremy L. Thompson 
380ea61e9acSJeremy L Thompson   @param[in]  ceed     Ceed context to set delegate of
3817a982d89SJeremy L. Thompson   @param[out] delegate Address to set the delegate to
3827a982d89SJeremy L. Thompson 
3837a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3847a982d89SJeremy L. Thompson 
3857a982d89SJeremy L. Thompson   @ref Backend
3867a982d89SJeremy L. Thompson **/
3877a982d89SJeremy L. Thompson int CeedSetDelegate(Ceed ceed, Ceed delegate) {
3887a982d89SJeremy L. Thompson   ceed->delegate   = delegate;
3897a982d89SJeremy L. Thompson   delegate->parent = ceed;
390e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3917a982d89SJeremy L. Thompson }
3927a982d89SJeremy L. Thompson 
3937a982d89SJeremy L. Thompson /**
3947a982d89SJeremy L. Thompson   @brief Retrieve a delegate Ceed context for a specific object type
3957a982d89SJeremy L. Thompson 
396ea61e9acSJeremy L Thompson   @param[in]  ceed     Ceed context to retrieve delegate of
3977a982d89SJeremy L. Thompson   @param[out] delegate Address to save the delegate to
398d1d35e2fSjeremylt   @param[in]  obj_name Name of the object type to retrieve delegate for
3997a982d89SJeremy L. Thompson 
4007a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4017a982d89SJeremy L. Thompson 
4027a982d89SJeremy L. Thompson   @ref Backend
4037a982d89SJeremy L. Thompson **/
404d1d35e2fSjeremylt int CeedGetObjectDelegate(Ceed ceed, Ceed *delegate, const char *obj_name) {
4057a982d89SJeremy L. Thompson   // Check for object delegate
4062b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < ceed->obj_delegate_count; i++) {
407d1d35e2fSjeremylt     if (!strcmp(obj_name, ceed->obj_delegates->obj_name)) {
408d1d35e2fSjeremylt       *delegate = ceed->obj_delegates->delegate;
409e15f9bd0SJeremy L Thompson       return CEED_ERROR_SUCCESS;
4107a982d89SJeremy L. Thompson     }
4112b730f8bSJeremy L Thompson   }
4127a982d89SJeremy L. Thompson 
4137a982d89SJeremy L. Thompson   // Use default delegate if no object delegate
4142b730f8bSJeremy L Thompson   CeedCall(CeedGetDelegate(ceed, delegate));
415e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4167a982d89SJeremy L. Thompson }
4177a982d89SJeremy L. Thompson 
4187a982d89SJeremy L. Thompson /**
4197a982d89SJeremy L. Thompson   @brief Set a delegate Ceed context for a specific object type
4207a982d89SJeremy L. Thompson 
421ea61e9acSJeremy L Thompson   This function allows a Ceed context to set a delegate Ceed context for a given type of Ceed object.
422ea61e9acSJeremy L Thompson     All backend implementations default to the delegate Ceed context for this object.
423ea61e9acSJeremy L Thompson     For example, CeedSetObjectDelegate(ceed, refceed, "Basis") uses refceed implementations for all CeedBasis backend functions.
4247a982d89SJeremy L. Thompson 
425ea61e9acSJeremy L Thompson   @param[in,out] ceed     Ceed context to set delegate of
4267a982d89SJeremy L. Thompson   @param[out]    delegate Address to set the delegate to
427d1d35e2fSjeremylt   @param[in]     obj_name Name of the object type to set delegate for
4287a982d89SJeremy L. Thompson 
4297a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4307a982d89SJeremy L. Thompson 
4317a982d89SJeremy L. Thompson   @ref Backend
4327a982d89SJeremy L. Thompson **/
433d1d35e2fSjeremylt int CeedSetObjectDelegate(Ceed ceed, Ceed delegate, const char *obj_name) {
434d1d35e2fSjeremylt   CeedInt count = ceed->obj_delegate_count;
4357a982d89SJeremy L. Thompson 
4367a982d89SJeremy L. Thompson   // Malloc or Realloc
4377a982d89SJeremy L. Thompson   if (count) {
4382b730f8bSJeremy L Thompson     CeedCall(CeedRealloc(count + 1, &ceed->obj_delegates));
4397a982d89SJeremy L. Thompson   } else {
4402b730f8bSJeremy L Thompson     CeedCall(CeedCalloc(1, &ceed->obj_delegates));
4417a982d89SJeremy L. Thompson   }
442d1d35e2fSjeremylt   ceed->obj_delegate_count++;
4437a982d89SJeremy L. Thompson 
4447a982d89SJeremy L. Thompson   // Set object delegate
445d1d35e2fSjeremylt   ceed->obj_delegates[count].delegate = delegate;
4462b730f8bSJeremy L Thompson   CeedCall(CeedStringAllocCopy(obj_name, &ceed->obj_delegates[count].obj_name));
4477a982d89SJeremy L. Thompson 
4487a982d89SJeremy L. Thompson   // Set delegate parent
4497a982d89SJeremy L. Thompson   delegate->parent = ceed;
450e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4517a982d89SJeremy L. Thompson }
4527a982d89SJeremy L. Thompson 
4537a982d89SJeremy L. Thompson /**
4547a982d89SJeremy L. Thompson   @brief Get the fallback resource for CeedOperators
4557a982d89SJeremy L. Thompson 
456ea61e9acSJeremy L Thompson   @param[in]  ceed     Ceed context
4577a982d89SJeremy L. Thompson   @param[out] resource Variable to store fallback resource
4587a982d89SJeremy L. Thompson 
4597a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4607a982d89SJeremy L. Thompson 
4617a982d89SJeremy L. Thompson   @ref Backend
4627a982d89SJeremy L. Thompson **/
4637a982d89SJeremy L. Thompson int CeedGetOperatorFallbackResource(Ceed ceed, const char **resource) {
464d1d35e2fSjeremylt   *resource = (const char *)ceed->op_fallback_resource;
465e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4667a982d89SJeremy L. Thompson }
4677a982d89SJeremy L. Thompson 
4687a982d89SJeremy L. Thompson /**
4698687e1d4SJeremy L Thompson   @brief Get the fallback Ceed for CeedOperators
4708687e1d4SJeremy L Thompson 
471ea61e9acSJeremy L Thompson   @param[in]  ceed          Ceed context
4728687e1d4SJeremy L Thompson   @param[out] fallback_ceed Variable to store fallback Ceed
4738687e1d4SJeremy L Thompson 
4748687e1d4SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
4758687e1d4SJeremy L Thompson 
4768687e1d4SJeremy L Thompson   @ref Backend
4778687e1d4SJeremy L Thompson **/
4788687e1d4SJeremy L Thompson int CeedGetOperatorFallbackCeed(Ceed ceed, Ceed *fallback_ceed) {
479d04bbc78SJeremy L Thompson   if (ceed->has_valid_op_fallback_resource) {
480d04bbc78SJeremy L Thompson     CeedDebug256(ceed, 1, "---------- CeedOperator Fallback ----------\n");
4812b730f8bSJeremy L Thompson     CeedDebug(ceed, "Getting fallback from %s to %s\n", ceed->resource, ceed->op_fallback_resource);
482d04bbc78SJeremy L Thompson   }
4838687e1d4SJeremy L Thompson 
484d04bbc78SJeremy L Thompson   // Create fallback Ceed if uninitalized
485d04bbc78SJeremy L Thompson   if (!ceed->op_fallback_ceed && ceed->has_valid_op_fallback_resource) {
48613f886e9SJeremy L Thompson     CeedDebug(ceed, "Creating fallback Ceed");
487d04bbc78SJeremy L Thompson 
4888687e1d4SJeremy L Thompson     Ceed        fallback_ceed;
489d04bbc78SJeremy L Thompson     const char *fallback_resource;
490d04bbc78SJeremy L Thompson 
4912b730f8bSJeremy L Thompson     CeedCall(CeedGetOperatorFallbackResource(ceed, &fallback_resource));
4922b730f8bSJeremy L Thompson     CeedCall(CeedInit(fallback_resource, &fallback_ceed));
4938687e1d4SJeremy L Thompson     fallback_ceed->op_fallback_parent = ceed;
4948687e1d4SJeremy L Thompson     fallback_ceed->Error              = ceed->Error;
4958687e1d4SJeremy L Thompson     ceed->op_fallback_ceed            = fallback_ceed;
4968687e1d4SJeremy L Thompson   }
4978687e1d4SJeremy L Thompson   *fallback_ceed = ceed->op_fallback_ceed;
4988687e1d4SJeremy L Thompson 
4998687e1d4SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5008687e1d4SJeremy L Thompson }
5018687e1d4SJeremy L Thompson 
5028687e1d4SJeremy L Thompson /**
503ea61e9acSJeremy L Thompson   @brief Set the fallback resource for CeedOperators.
504*4385fb7fSSebastian Grimberg 
505ea61e9acSJeremy L Thompson   The current resource, if any, is freed by calling this function.
506ea61e9acSJeremy L Thompson   This string is freed upon the destruction of the Ceed context.
5077a982d89SJeremy L. Thompson 
508ea61e9acSJeremy L Thompson   @param[in,out] ceed     Ceed context
509ea61e9acSJeremy L Thompson   @param[in]     resource Fallback resource to set
5107a982d89SJeremy L. Thompson 
5117a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5127a982d89SJeremy L. Thompson 
5137a982d89SJeremy L. Thompson   @ref Backend
5147a982d89SJeremy L. Thompson **/
5157a982d89SJeremy L. Thompson int CeedSetOperatorFallbackResource(Ceed ceed, const char *resource) {
5167a982d89SJeremy L. Thompson   // Free old
5172b730f8bSJeremy L Thompson   CeedCall(CeedFree(&ceed->op_fallback_resource));
5187a982d89SJeremy L. Thompson 
5197a982d89SJeremy L. Thompson   // Set new
5202b730f8bSJeremy L Thompson   CeedCall(CeedStringAllocCopy(resource, (char **)&ceed->op_fallback_resource));
521d04bbc78SJeremy L Thompson 
522d04bbc78SJeremy L Thompson   // Check validity
5232b730f8bSJeremy L Thompson   ceed->has_valid_op_fallback_resource = ceed->op_fallback_resource && ceed->resource && strcmp(ceed->op_fallback_resource, ceed->resource);
524d04bbc78SJeremy L Thompson 
525e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5267a982d89SJeremy L. Thompson }
5277a982d89SJeremy L. Thompson 
5287a982d89SJeremy L. Thompson /**
529ea61e9acSJeremy L Thompson   @brief Get the parent Ceed context associated with a fallback Ceed context for a CeedOperator
5307a982d89SJeremy L. Thompson 
531ea61e9acSJeremy L Thompson   @param[in]  ceed   Ceed context
5327a982d89SJeremy L. Thompson   @param[out] parent Variable to store parent Ceed context
5337a982d89SJeremy L. Thompson 
5347a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5357a982d89SJeremy L. Thompson 
5367a982d89SJeremy L. Thompson   @ref Backend
5377a982d89SJeremy L. Thompson **/
5387a982d89SJeremy L. Thompson int CeedGetOperatorFallbackParentCeed(Ceed ceed, Ceed *parent) {
539d1d35e2fSjeremylt   *parent = ceed->op_fallback_parent;
540e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5417a982d89SJeremy L. Thompson }
5427a982d89SJeremy L. Thompson 
5437a982d89SJeremy L. Thompson /**
5449525855cSJeremy L Thompson   @brief Flag Ceed context as deterministic
5459525855cSJeremy L Thompson 
546ea61e9acSJeremy L Thompson   @param[in]  ceed             Ceed to flag as deterministic
54796b902e2Sjeremylt   @param[out] is_deterministic Deterministic status to set
5489525855cSJeremy L Thompson 
5499525855cSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
5509525855cSJeremy L Thompson 
5519525855cSJeremy L Thompson   @ref Backend
5529525855cSJeremy L Thompson **/
553d1d35e2fSjeremylt int CeedSetDeterministic(Ceed ceed, bool is_deterministic) {
554d1d35e2fSjeremylt   ceed->is_deterministic = is_deterministic;
555e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5569525855cSJeremy L Thompson }
5579525855cSJeremy L Thompson 
5589525855cSJeremy L Thompson /**
5597a982d89SJeremy L. Thompson   @brief Set a backend function
5607a982d89SJeremy L. Thompson 
561ea61e9acSJeremy L Thompson   This function is used for a backend to set the function associated with the Ceed objects.
562ea61e9acSJeremy L Thompson     For example, CeedSetBackendFunction(ceed, "Ceed", ceed, "VectorCreate", BackendVectorCreate) sets the backend implementation of 'CeedVectorCreate'
563ea61e9acSJeremy L Thompson and CeedSetBackendFunction(ceed, "Basis", basis, "Apply", BackendBasisApply) sets the backend implementation of 'CeedBasisApply'. Note, the prefix
564ea61e9acSJeremy L Thompson 'Ceed' is not required for the object type ("Basis" vs "CeedBasis").
5657a982d89SJeremy L. Thompson 
566ea61e9acSJeremy L Thompson   @param[in]  ceed      Ceed context for error handling
567ea61e9acSJeremy L Thompson   @param[in]  type      Type of Ceed object to set function for
5687a982d89SJeremy L. Thompson   @param[out] object    Ceed object to set function for
569ea61e9acSJeremy L Thompson   @param[in]  func_name Name of function to set
570ea61e9acSJeremy L Thompson   @param[in]  f         Function to set
5717a982d89SJeremy L. Thompson 
5727a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5737a982d89SJeremy L. Thompson 
5747a982d89SJeremy L. Thompson   @ref Backend
5757a982d89SJeremy L. Thompson **/
5762b730f8bSJeremy L Thompson int CeedSetBackendFunction(Ceed ceed, const char *type, void *object, const char *func_name, int (*f)()) {
577d1d35e2fSjeremylt   char lookup_name[CEED_MAX_RESOURCE_LEN + 1] = "";
5787a982d89SJeremy L. Thompson 
5797a982d89SJeremy L. Thompson   // Build lookup name
5802b730f8bSJeremy L Thompson   if (strcmp(type, "Ceed")) strncat(lookup_name, "Ceed", CEED_MAX_RESOURCE_LEN);
581d1d35e2fSjeremylt   strncat(lookup_name, type, CEED_MAX_RESOURCE_LEN);
582d1d35e2fSjeremylt   strncat(lookup_name, func_name, CEED_MAX_RESOURCE_LEN);
5837a982d89SJeremy L. Thompson 
5847a982d89SJeremy L. Thompson   // Find and use offset
5852b730f8bSJeremy L Thompson   for (CeedInt i = 0; ceed->f_offsets[i].func_name; i++) {
586d1d35e2fSjeremylt     if (!strcmp(ceed->f_offsets[i].func_name, lookup_name)) {
587d1d35e2fSjeremylt       size_t offset          = ceed->f_offsets[i].offset;
5887a982d89SJeremy L. Thompson       int (**fpointer)(void) = (int (**)(void))((char *)object + offset);  // *NOPAD*
5897a982d89SJeremy L. Thompson       *fpointer              = f;
590e15f9bd0SJeremy L Thompson       return CEED_ERROR_SUCCESS;
5917a982d89SJeremy L. Thompson     }
5922b730f8bSJeremy L Thompson   }
5937a982d89SJeremy L. Thompson 
5947a982d89SJeremy L. Thompson   // LCOV_EXCL_START
5952b730f8bSJeremy L Thompson   return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Requested function '%s' was not found for CEED object '%s'", func_name, type);
5967a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
5977a982d89SJeremy L. Thompson }
5987a982d89SJeremy L. Thompson 
5997a982d89SJeremy L. Thompson /**
6007a982d89SJeremy L. Thompson   @brief Retrieve backend data for a Ceed context
6017a982d89SJeremy L. Thompson 
602ea61e9acSJeremy L Thompson   @param[in]  ceed Ceed context to retrieve data of
6037a982d89SJeremy L. Thompson   @param[out] data Address to save data to
6047a982d89SJeremy L. Thompson 
6057a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6067a982d89SJeremy L. Thompson 
6077a982d89SJeremy L. Thompson   @ref Backend
6087a982d89SJeremy L. Thompson **/
609777ff853SJeremy L Thompson int CeedGetData(Ceed ceed, void *data) {
610777ff853SJeremy L Thompson   *(void **)data = ceed->data;
611e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6127a982d89SJeremy L. Thompson }
6137a982d89SJeremy L. Thompson 
6147a982d89SJeremy L. Thompson /**
6157a982d89SJeremy L. Thompson   @brief Set backend data for a Ceed context
6167a982d89SJeremy L. Thompson 
617ea61e9acSJeremy L Thompson   @param[in,out] ceed Ceed context to set data of
618ea61e9acSJeremy L Thompson   @param[in]     data Address of data to set
6197a982d89SJeremy L. Thompson 
6207a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6217a982d89SJeremy L. Thompson 
6227a982d89SJeremy L. Thompson   @ref Backend
6237a982d89SJeremy L. Thompson **/
624777ff853SJeremy L Thompson int CeedSetData(Ceed ceed, void *data) {
625777ff853SJeremy L Thompson   ceed->data = data;
626e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6277a982d89SJeremy L. Thompson }
6287a982d89SJeremy L. Thompson 
62934359f16Sjeremylt /**
63034359f16Sjeremylt   @brief Increment the reference counter for a Ceed context
63134359f16Sjeremylt 
632ea61e9acSJeremy L Thompson   @param[in,out] ceed Ceed context to increment the reference counter
63334359f16Sjeremylt 
63434359f16Sjeremylt   @return An error code: 0 - success, otherwise - failure
63534359f16Sjeremylt 
63634359f16Sjeremylt   @ref Backend
63734359f16Sjeremylt **/
6389560d06aSjeremylt int CeedReference(Ceed ceed) {
63934359f16Sjeremylt   ceed->ref_count++;
64034359f16Sjeremylt   return CEED_ERROR_SUCCESS;
64134359f16Sjeremylt }
64234359f16Sjeremylt 
6437a982d89SJeremy L. Thompson /// @}
6447a982d89SJeremy L. Thompson 
6457a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
6467a982d89SJeremy L. Thompson /// Ceed Public API
6477a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
6487a982d89SJeremy L. Thompson /// @addtogroup CeedUser
6497a982d89SJeremy L. Thompson /// @{
6507a982d89SJeremy L. Thompson 
6517a982d89SJeremy L. Thompson /**
65292ee7d1cSjeremylt   @brief Get the list of available resource names for Ceed contexts
653*4385fb7fSSebastian Grimberg 
654ea61e9acSJeremy L Thompson   Note: The caller is responsible for `free()`ing the resources and priorities arrays, but should not `free()` the contents of the resources
655ea61e9acSJeremy L Thompson array.
65622e44211Sjeremylt 
65792ee7d1cSjeremylt   @param[out] n          Number of available resources
65892ee7d1cSjeremylt   @param[out] resources  List of available resource names
65922e44211Sjeremylt   @param[out] priorities Resource name prioritization values, lower is better
66022e44211Sjeremylt 
66122e44211Sjeremylt   @return An error code: 0 - success, otherwise - failure
66222e44211Sjeremylt 
66322e44211Sjeremylt   @ref User
66422e44211Sjeremylt **/
66522e44211Sjeremylt // LCOV_EXCL_START
6662b730f8bSJeremy L Thompson int CeedRegistryGetList(size_t *n, char ***const resources, CeedInt **priorities) {
667d0c91ce9Sjeremylt   *n         = 0;
6689ff86846Sjeremylt   *resources = malloc(num_backends * sizeof(**resources));
6692b730f8bSJeremy L Thompson   if (!resources) return CeedError(NULL, CEED_ERROR_MAJOR, "malloc() failure");
6709ff86846Sjeremylt   if (priorities) {
6719ff86846Sjeremylt     *priorities = malloc(num_backends * sizeof(**priorities));
6722b730f8bSJeremy L Thompson     if (!priorities) return CeedError(NULL, CEED_ERROR_MAJOR, "malloc() failure");
6739ff86846Sjeremylt   }
67422e44211Sjeremylt   for (size_t i = 0; i < num_backends; i++) {
675d0c91ce9Sjeremylt     // Only report compiled backends
676d0c91ce9Sjeremylt     if (backends[i].priority < CEED_MAX_BACKEND_PRIORITY) {
67722e44211Sjeremylt       *resources[i] = backends[i].prefix;
6789ff86846Sjeremylt       if (priorities) *priorities[i] = backends[i].priority;
679d0c91ce9Sjeremylt       *n += 1;
680d0c91ce9Sjeremylt     }
681d0c91ce9Sjeremylt   }
6822b730f8bSJeremy L Thompson   if (*n == 0) {
68378464608Sjeremylt     // LCOV_EXCL_START
68478464608Sjeremylt     return CeedError(NULL, CEED_ERROR_MAJOR, "No backends installed");
68578464608Sjeremylt     // LCOV_EXCL_STOP
6862b730f8bSJeremy L Thompson   }
687d0c91ce9Sjeremylt   *resources = realloc(*resources, *n * sizeof(**resources));
6882b730f8bSJeremy L Thompson   if (!resources) return CeedError(NULL, CEED_ERROR_MAJOR, "realloc() failure");
689d0c91ce9Sjeremylt   if (priorities) {
690d0c91ce9Sjeremylt     *priorities = realloc(*priorities, *n * sizeof(**priorities));
6912b730f8bSJeremy L Thompson     if (!priorities) return CeedError(NULL, CEED_ERROR_MAJOR, "realloc() failure");
69222e44211Sjeremylt   }
69322e44211Sjeremylt   return CEED_ERROR_SUCCESS;
69445f1e315Sjeremylt }
69522e44211Sjeremylt // LCOV_EXCL_STOP
69622e44211Sjeremylt 
69722e44211Sjeremylt /**
698d79b80ecSjeremylt   @brief Initialize a \ref Ceed context to use the specified resource.
699*4385fb7fSSebastian Grimberg 
700ea61e9acSJeremy L Thompson   Note: Prefixing the resource with "help:" (e.g. "help:/cpu/self") will result in CeedInt printing the current libCEED version number and a
701ea61e9acSJeremy L Thompson list of current available backend resources to stderr.
702b11c1e72Sjeremylt 
703ea61e9acSJeremy L Thompson   @param[in]  resource Resource to use, e.g., "/cpu/self"
704ea61e9acSJeremy L Thompson   @param[out] ceed     The library context
705b11c1e72Sjeremylt   @sa CeedRegister() CeedDestroy()
706b11c1e72Sjeremylt 
707b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
708dfdf5a53Sjeremylt 
7097a982d89SJeremy L. Thompson   @ref User
710b11c1e72Sjeremylt **/
711d7b241e6Sjeremylt int CeedInit(const char *resource, Ceed *ceed) {
7122b730f8bSJeremy L Thompson   size_t match_len = 0, match_index = UINT_MAX, match_priority = CEED_MAX_BACKEND_PRIORITY, priority;
713d7b241e6Sjeremylt 
714fe2413ffSjeremylt   // Find matching backend
7152b730f8bSJeremy L Thompson   if (!resource) {
71613873f79Sjeremylt     // LCOV_EXCL_START
717e15f9bd0SJeremy L Thompson     return CeedError(NULL, CEED_ERROR_MAJOR, "No resource provided");
71813873f79Sjeremylt     // LCOV_EXCL_STOP
7192b730f8bSJeremy L Thompson   }
7202b730f8bSJeremy L Thompson   CeedCall(CeedRegisterAll());
72113873f79Sjeremylt 
72222e44211Sjeremylt   // Check for help request
72322e44211Sjeremylt   const char *help_prefix = "help";
7242b730f8bSJeremy L Thompson   size_t      match_help  = 0;
7252b730f8bSJeremy L Thompson   while (match_help < 4 && resource[match_help] == help_prefix[match_help]) match_help++;
72622e44211Sjeremylt   if (match_help == 4) {
7272b730f8bSJeremy L Thompson     fprintf(stderr, "libCEED version: %d.%d%d%s\n", CEED_VERSION_MAJOR, CEED_VERSION_MINOR, CEED_VERSION_PATCH,
72822e44211Sjeremylt             CEED_VERSION_RELEASE ? "" : "+development");
72992ee7d1cSjeremylt     fprintf(stderr, "Available backend resources:\n");
73022e44211Sjeremylt     for (size_t i = 0; i < num_backends; i++) {
731d0c91ce9Sjeremylt       // Only report compiled backends
7322b730f8bSJeremy L Thompson       if (backends[i].priority < CEED_MAX_BACKEND_PRIORITY) 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 
740ea61e9acSJeremy L Thompson   // Find best match, computed as number of matching characters from requested resource stem
7412b730f8bSJeremy L Thompson   size_t stem_length = 0;
7422b730f8bSJeremy L Thompson   while (resource[stem_length + match_help] && resource[stem_length + match_help] != ':') stem_length++;
743d7b241e6Sjeremylt   for (size_t i = 0; i < num_backends; i++) {
7442b730f8bSJeremy L Thompson     size_t      n      = 0;
745d7b241e6Sjeremylt     const char *prefix = backends[i].prefix;
7462b730f8bSJeremy L Thompson     while (prefix[n] && prefix[n] == resource[n + match_help]) n++;
747d7b241e6Sjeremylt     priority = backends[i].priority;
748d1d35e2fSjeremylt     if (n > match_len || (n == match_len && match_priority > priority)) {
749d1d35e2fSjeremylt       match_len      = n;
750d1d35e2fSjeremylt       match_priority = priority;
751f7e22acaSJeremy L Thompson       match_index    = i;
752d7b241e6Sjeremylt     }
753d7b241e6Sjeremylt   }
7549c9a0587SLeila Ghaffari   // Using Levenshtein distance to find closest match
7559c9a0587SLeila Ghaffari   if (match_len <= 1 || match_len != stem_length) {
756203015caSLeila Ghaffari     // LCOV_EXCL_START
7579c9a0587SLeila Ghaffari     size_t lev_dis   = UINT_MAX;
758f7e22acaSJeremy L Thompson     size_t lev_index = UINT_MAX, lev_priority = CEED_MAX_BACKEND_PRIORITY;
7599c9a0587SLeila Ghaffari     for (size_t i = 0; i < num_backends; i++) {
7609c9a0587SLeila Ghaffari       const char *prefix        = backends[i].prefix;
7619c9a0587SLeila Ghaffari       size_t      prefix_length = strlen(backends[i].prefix);
7629c9a0587SLeila Ghaffari       size_t      min_len       = (prefix_length < stem_length) ? prefix_length : stem_length;
763092904ddSLeila Ghaffari       size_t      column[min_len + 1];
764092904ddSLeila Ghaffari       for (size_t j = 0; j <= min_len; j++) column[j] = j;
7659c9a0587SLeila Ghaffari       for (size_t j = 1; j <= min_len; j++) {
7669c9a0587SLeila Ghaffari         column[0] = j;
7679c9a0587SLeila Ghaffari         for (size_t k = 1, last_diag = j - 1; k <= min_len; k++) {
768092904ddSLeila Ghaffari           size_t old_diag = column[k];
7699c9a0587SLeila Ghaffari           size_t min_1    = (column[k] < column[k - 1]) ? column[k] + 1 : column[k - 1] + 1;
7709c9a0587SLeila Ghaffari           size_t min_2    = last_diag + (resource[k - 1] == prefix[j - 1] ? 0 : 1);
7719c9a0587SLeila Ghaffari           column[k]       = (min_1 < min_2) ? min_1 : min_2;
7729c9a0587SLeila Ghaffari           last_diag       = old_diag;
7739c9a0587SLeila Ghaffari         }
7749c9a0587SLeila Ghaffari       }
7759c9a0587SLeila Ghaffari       size_t n = column[min_len];
7769c9a0587SLeila Ghaffari       priority = backends[i].priority;
7772b730f8bSJeremy L Thompson       if (n < lev_dis || (n == lev_dis && lev_priority > priority)) {
7789c9a0587SLeila Ghaffari         lev_dis      = n;
7799c9a0587SLeila Ghaffari         lev_priority = priority;
780f7e22acaSJeremy L Thompson         lev_index    = i;
7819c9a0587SLeila Ghaffari       }
7829c9a0587SLeila Ghaffari     }
783f7e22acaSJeremy L Thompson     const char *prefix_lev = backends[lev_index].prefix;
7842b730f8bSJeremy L Thompson     size_t      lev_length = 0;
7852b730f8bSJeremy L Thompson     while (prefix_lev[lev_length] && prefix_lev[lev_length] != '\0') lev_length++;
7869c9a0587SLeila Ghaffari     size_t m = (lev_length < stem_length) ? lev_length : stem_length;
7879c9a0587SLeila Ghaffari     if (lev_dis + 1 >= m) {
7882b730f8bSJeremy L Thompson       return CeedError(NULL, CEED_ERROR_MAJOR, "No suitable backend: %s", resource);
7899c9a0587SLeila Ghaffari     } else {
7902b730f8bSJeremy L Thompson       return CeedError(NULL, CEED_ERROR_MAJOR,
7912b730f8bSJeremy L Thompson                        "No suitable backend: %s\n"
7922b730f8bSJeremy L Thompson                        "Closest match: %s",
7932b730f8bSJeremy L Thompson                        resource, backends[lev_index].prefix);
7942bbc7fe8Sjeremylt     }
795203015caSLeila Ghaffari     // LCOV_EXCL_STOP
7969c9a0587SLeila Ghaffari   }
797fe2413ffSjeremylt 
798fe2413ffSjeremylt   // Setup Ceed
7992b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, ceed));
8002b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, &(*ceed)->jit_source_roots));
801bc81ce41Sjeremylt   const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER");
8022b730f8bSJeremy L Thompson   if (!ceed_error_handler) ceed_error_handler = "abort";
8032b730f8bSJeremy L Thompson   if (!strcmp(ceed_error_handler, "exit")) (*ceed)->Error = CeedErrorExit;
8042b730f8bSJeremy L Thompson   else if (!strcmp(ceed_error_handler, "store")) (*ceed)->Error = CeedErrorStore;
8052b730f8bSJeremy L Thompson   else (*ceed)->Error = CeedErrorAbort;
806d1d35e2fSjeremylt   memcpy((*ceed)->err_msg, "No error message stored", 24);
807d1d35e2fSjeremylt   (*ceed)->ref_count = 1;
808d7b241e6Sjeremylt   (*ceed)->data      = NULL;
809fe2413ffSjeremylt 
810fe2413ffSjeremylt   // Set lookup table
811d1d35e2fSjeremylt   FOffset f_offsets[] = {
8126e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, Error),
8136e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, GetPreferredMemType),
8146e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, Destroy),
815f8902d9eSjeremylt       CEED_FTABLE_ENTRY(Ceed, VectorCreate),
8166e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreate),
817fc0567d9Srezgarshakeri       CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateOriented),
8186e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked),
8196e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1),
8206e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, BasisCreateH1),
82150c301a5SRezgar Shakeri       CEED_FTABLE_ENTRY(Ceed, BasisCreateHdiv),
822c4e3f59bSSebastian Grimberg       CEED_FTABLE_ENTRY(Ceed, BasisCreateHcurl),
8236e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, TensorContractCreate),
8246e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, QFunctionCreate),
825777ff853SJeremy L Thompson       CEED_FTABLE_ENTRY(Ceed, QFunctionContextCreate),
8266e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, OperatorCreate),
8276e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate),
8289c774eddSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, HasValidArray),
8299c774eddSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, HasBorrowedArrayOfType),
8306e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, SetArray),
8316a6c615bSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, TakeArray),
8326e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, SetValue),
833f48ed27dSnbeams       CEED_FTABLE_ENTRY(CeedVector, SyncArray),
8346e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, GetArray),
8356e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, GetArrayRead),
8369c774eddSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, GetArrayWrite),
8376e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, RestoreArray),
8386e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead),
839547d9b97Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, Norm),
840e0dd3b27Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, Scale),
8410f7fd0f8Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, AXPY),
8425fb68f37SKaren (Ren) Stengel       CEED_FTABLE_ENTRY(CeedVector, AXPBY),
8430f7fd0f8Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, PointwiseMult),
844d99fa3c5SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, Reciprocal),
8456e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, Destroy),
8466e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedElemRestriction, Apply),
8476e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock),
848bd33150aSjeremylt       CEED_FTABLE_ENTRY(CeedElemRestriction, GetOffsets),
8496e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy),
8506e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedBasis, Apply),
8516e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedBasis, Destroy),
8526e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedTensorContract, Apply),
8536e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedTensorContract, Destroy),
8546e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedQFunction, Apply),
8558c84ac63Sjeremylt       CEED_FTABLE_ENTRY(CeedQFunction, SetCUDAUserFunction),
8568c84ac63Sjeremylt       CEED_FTABLE_ENTRY(CeedQFunction, SetHIPUserFunction),
8576e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedQFunction, Destroy),
8589c774eddSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, HasValidData),
8599c774eddSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, HasBorrowedDataOfType),
860777ff853SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, SetData),
861891038deSjeremylt       CEED_FTABLE_ENTRY(CeedQFunctionContext, TakeData),
862777ff853SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, GetData),
86328bfd0b7SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, GetDataRead),
864777ff853SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, RestoreData),
86528bfd0b7SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, RestoreDataRead),
8662e64a2b9SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, DataDestroy),
867777ff853SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, Destroy),
86880ac2e43SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunction),
86970a7ffb3SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunctionUpdate),
87080ac2e43SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleDiagonal),
8719e9210b8SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddDiagonal),
87280ac2e43SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssemblePointBlockDiagonal),
8739e9210b8SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddPointBlockDiagonal),
874e2f04181SAndrew T. Barker       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleSymbolic),
875e2f04181SAndrew T. Barker       CEED_FTABLE_ENTRY(CeedOperator, LinearAssemble),
876cefa2673SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleSingle),
877713f43c3Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, CreateFDMElementInverse),
8786e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, Apply),
879250756a7Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, ApplyComposite),
880cae8b89aSjeremylt       CEED_FTABLE_ENTRY(CeedOperator, ApplyAdd),
881250756a7Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, ApplyAddComposite),
8826e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian),
8836e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, Destroy),
8846e79d475Sjeremylt       {NULL, 0}  // End of lookup table - used in SetBackendFunction loop
8851dfeef1dSjeremylt   };
886fe2413ffSjeremylt 
8872b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(sizeof(f_offsets), &(*ceed)->f_offsets));
888d1d35e2fSjeremylt   memcpy((*ceed)->f_offsets, f_offsets, sizeof(f_offsets));
889fe2413ffSjeremylt 
8905107b09fSJeremy L Thompson   // Set fallback for advanced CeedOperator functions
891e2f04181SAndrew T. Barker   const char fallbackresource[] = "";
8922b730f8bSJeremy L Thompson   CeedCall(CeedSetOperatorFallbackResource(*ceed, fallbackresource));
8935107b09fSJeremy L Thompson 
89460f9e2d6SJeremy L Thompson   // Record env variables CEED_DEBUG or DBG
8952b730f8bSJeremy L Thompson   (*ceed)->is_debug = !!getenv("CEED_DEBUG") || !!getenv("DEBUG") || !!getenv("DBG");
89660f9e2d6SJeremy L Thompson 
89722e44211Sjeremylt   // Copy resource prefix, if backend setup successful
8982b730f8bSJeremy L Thompson   CeedCall(CeedStringAllocCopy(backends[match_index].prefix, (char **)&(*ceed)->resource));
899ee5a26f2SJeremy L Thompson 
900ee5a26f2SJeremy L Thompson   // Set default JiT source root
901ea61e9acSJeremy L Thompson   // Note: there will always be the default root for every Ceed but all additional paths are added to the top-most parent
9022b730f8bSJeremy L Thompson   CeedCall(CeedAddJitSourceRoot(*ceed, (char *)CeedJitSourceRootDefault));
903ee5a26f2SJeremy L Thompson 
904d04bbc78SJeremy L Thompson   // Backend specific setup
9052b730f8bSJeremy L Thompson   CeedCall(backends[match_index].init(&resource[match_help], *ceed));
906d04bbc78SJeremy L Thompson 
907e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
908d7b241e6Sjeremylt }
909d7b241e6Sjeremylt 
910d7b241e6Sjeremylt /**
911ea61e9acSJeremy L Thompson   @brief Copy the pointer to a Ceed context.
912*4385fb7fSSebastian Grimberg 
913512bb800SJeremy L Thompson   Both pointers should be destroyed with `CeedDestroy()`.
914512bb800SJeremy L Thompson 
915512bb800SJeremy L Thompson   Note: If the value of `ceed_copy` passed to this function is non-NULL, then it is assumed that `ceed_copy` is a pointer to a Ceed context.
916512bb800SJeremy L Thompson         This Ceed context will be destroyed if `ceed_copy` is the only reference to this Ceed context.
9179560d06aSjeremylt 
918ea61e9acSJeremy L Thompson   @param[in]     ceed      Ceed context to copy reference to
919ea61e9acSJeremy L Thompson   @param[in,out] ceed_copy Variable to store copied reference
9209560d06aSjeremylt 
9219560d06aSjeremylt   @return An error code: 0 - success, otherwise - failure
9229560d06aSjeremylt 
9239560d06aSjeremylt   @ref User
9249560d06aSjeremylt **/
9259560d06aSjeremylt int CeedReferenceCopy(Ceed ceed, Ceed *ceed_copy) {
9262b730f8bSJeremy L Thompson   CeedCall(CeedReference(ceed));
9272b730f8bSJeremy L Thompson   CeedCall(CeedDestroy(ceed_copy));
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 
935ea61e9acSJeremy L Thompson   @param[in]  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 
950ea61e9acSJeremy L Thompson   @param[in]  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   if (ceed->GetPreferredMemType) {
9592b730f8bSJeremy L Thompson     CeedCall(ceed->GetPreferredMemType(mem_type));
960c907536fSjeremylt   } else {
961c263cd57Sjeremylt     Ceed delegate;
9622b730f8bSJeremy L Thompson     CeedCall(CeedGetDelegate(ceed, &delegate));
963c263cd57Sjeremylt 
964c263cd57Sjeremylt     if (delegate) {
9652b730f8bSJeremy L Thompson       CeedCall(CeedGetPreferredMemType(delegate, mem_type));
966c263cd57Sjeremylt     } else {
967d1d35e2fSjeremylt       *mem_type = CEED_MEM_HOST;
968c907536fSjeremylt     }
969c263cd57Sjeremylt   }
970e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
971c907536fSjeremylt }
972c907536fSjeremylt 
973c907536fSjeremylt /**
9749525855cSJeremy L Thompson   @brief Get deterministic status of Ceed
9759525855cSJeremy L Thompson 
9769525855cSJeremy L Thompson   @param[in]  ceed             Ceed
977d1d35e2fSjeremylt   @param[out] is_deterministic Variable to store deterministic status
9789525855cSJeremy L Thompson 
9799525855cSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
9809525855cSJeremy L Thompson 
9819525855cSJeremy L Thompson   @ref User
9829525855cSJeremy L Thompson **/
983d1d35e2fSjeremylt int CeedIsDeterministic(Ceed ceed, bool *is_deterministic) {
984d1d35e2fSjeremylt   *is_deterministic = ceed->is_deterministic;
985e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
9869525855cSJeremy L Thompson }
9879525855cSJeremy L Thompson 
9889525855cSJeremy L Thompson /**
989ee5a26f2SJeremy L Thompson   @brief Set additional JiT source root for Ceed
990ee5a26f2SJeremy L Thompson 
991ea61e9acSJeremy L Thompson   @param[in,out] ceed            Ceed
992ee5a26f2SJeremy L Thompson   @param[in]     jit_source_root Absolute path to additional JiT source directory
993ee5a26f2SJeremy L Thompson 
994ee5a26f2SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
995ee5a26f2SJeremy L Thompson 
996ee5a26f2SJeremy L Thompson   @ref User
997ee5a26f2SJeremy L Thompson **/
998ee5a26f2SJeremy L Thompson int CeedAddJitSourceRoot(Ceed ceed, const char *jit_source_root) {
9996155f12fSJeremy L Thompson   Ceed ceed_parent;
1000ee5a26f2SJeremy L Thompson 
10012b730f8bSJeremy L Thompson   CeedCall(CeedGetParent(ceed, &ceed_parent));
10026155f12fSJeremy L Thompson 
10036155f12fSJeremy L Thompson   CeedInt index       = ceed_parent->num_jit_source_roots;
1004ee5a26f2SJeremy L Thompson   size_t  path_length = strlen(jit_source_root);
10052b730f8bSJeremy L Thompson   CeedCall(CeedRealloc(index + 1, &ceed_parent->jit_source_roots));
10062b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(path_length + 1, &ceed_parent->jit_source_roots[index]));
1007d602d780SJeremy L Thompson   memcpy(ceed_parent->jit_source_roots[index], jit_source_root, path_length);
10086155f12fSJeremy L Thompson   ceed_parent->num_jit_source_roots++;
1009ee5a26f2SJeremy L Thompson 
1010ee5a26f2SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1011ee5a26f2SJeremy L Thompson }
1012ee5a26f2SJeremy L Thompson 
1013ee5a26f2SJeremy L Thompson /**
10140a0da059Sjeremylt   @brief View a Ceed
10150a0da059Sjeremylt 
10160a0da059Sjeremylt   @param[in] ceed   Ceed to view
10170a0da059Sjeremylt   @param[in] stream Filestream to write to
10180a0da059Sjeremylt 
10190a0da059Sjeremylt   @return An error code: 0 - success, otherwise - failure
10200a0da059Sjeremylt 
10210a0da059Sjeremylt   @ref User
10220a0da059Sjeremylt **/
10230a0da059Sjeremylt int CeedView(Ceed ceed, FILE *stream) {
1024d1d35e2fSjeremylt   CeedMemType mem_type;
10250a0da059Sjeremylt 
10262b730f8bSJeremy L Thompson   CeedCall(CeedGetPreferredMemType(ceed, &mem_type));
10270a0da059Sjeremylt 
10282b730f8bSJeremy L Thompson   fprintf(stream,
10292b730f8bSJeremy L Thompson           "Ceed\n"
10300a0da059Sjeremylt           "  Ceed Resource: %s\n"
10310a0da059Sjeremylt           "  Preferred MemType: %s\n",
1032d1d35e2fSjeremylt           ceed->resource, CeedMemTypes[mem_type]);
1033e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
10340a0da059Sjeremylt }
10350a0da059Sjeremylt 
10360a0da059Sjeremylt /**
1037b11c1e72Sjeremylt   @brief Destroy a Ceed context
1038d7b241e6Sjeremylt 
1039ea61e9acSJeremy L Thompson   @param[in,out] ceed Address of Ceed context to destroy
1040b11c1e72Sjeremylt 
1041b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1042dfdf5a53Sjeremylt 
10437a982d89SJeremy L. Thompson   @ref User
1044b11c1e72Sjeremylt **/
1045d7b241e6Sjeremylt int CeedDestroy(Ceed *ceed) {
1046ad6481ceSJeremy L Thompson   if (!*ceed || --(*ceed)->ref_count > 0) {
1047ad6481ceSJeremy L Thompson     *ceed = NULL;
1048ad6481ceSJeremy L Thompson     return CEED_ERROR_SUCCESS;
1049ad6481ceSJeremy L Thompson   }
10502b730f8bSJeremy L Thompson   if ((*ceed)->delegate) CeedCall(CeedDestroy(&(*ceed)->delegate));
10510ace9bf2Sjeremylt 
1052d1d35e2fSjeremylt   if ((*ceed)->obj_delegate_count > 0) {
105392ae7e47SJeremy L Thompson     for (CeedInt i = 0; i < (*ceed)->obj_delegate_count; i++) {
10542b730f8bSJeremy L Thompson       CeedCall(CeedDestroy(&((*ceed)->obj_delegates[i].delegate)));
10552b730f8bSJeremy L Thompson       CeedCall(CeedFree(&(*ceed)->obj_delegates[i].obj_name));
1056aefd8378Sjeremylt     }
10572b730f8bSJeremy L Thompson     CeedCall(CeedFree(&(*ceed)->obj_delegates));
1058aefd8378Sjeremylt   }
10590ace9bf2Sjeremylt 
10602b730f8bSJeremy L Thompson   if ((*ceed)->Destroy) CeedCall((*ceed)->Destroy(*ceed));
10610ace9bf2Sjeremylt 
106292ae7e47SJeremy L Thompson   for (CeedInt i = 0; i < (*ceed)->num_jit_source_roots; i++) {
10632b730f8bSJeremy L Thompson     CeedCall(CeedFree(&(*ceed)->jit_source_roots[i]));
1064032e71eaSJeremy L Thompson   }
10652b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*ceed)->jit_source_roots));
1066032e71eaSJeremy L Thompson 
10672b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*ceed)->f_offsets));
10682b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*ceed)->resource));
10692b730f8bSJeremy L Thompson   CeedCall(CeedDestroy(&(*ceed)->op_fallback_ceed));
10702b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*ceed)->op_fallback_resource));
10712b730f8bSJeremy L Thompson   CeedCall(CeedFree(ceed));
1072e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1073d7b241e6Sjeremylt }
1074d7b241e6Sjeremylt 
1075f9982c62SWill Pazner // LCOV_EXCL_START
1076f9982c62SWill Pazner const char *CeedErrorFormat(Ceed ceed, const char *format, va_list *args) {
10772b730f8bSJeremy L Thompson   if (ceed->parent) return CeedErrorFormat(ceed->parent, format, args);
10782b730f8bSJeremy L Thompson   if (ceed->op_fallback_parent) return CeedErrorFormat(ceed->op_fallback_parent, format, args);
107978464608Sjeremylt   // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized
108078464608Sjeremylt   vsnprintf(ceed->err_msg, CEED_MAX_RESOURCE_LEN, format, *args);  // NOLINT
1081d1d35e2fSjeremylt   return ceed->err_msg;
1082f9982c62SWill Pazner }
1083f9982c62SWill Pazner // LCOV_EXCL_STOP
1084f9982c62SWill Pazner 
10857a982d89SJeremy L. Thompson /**
10867a982d89SJeremy L. Thompson   @brief Error handling implementation; use \ref CeedError instead.
10877a982d89SJeremy L. Thompson 
10887a982d89SJeremy L. Thompson   @ref Developer
10897a982d89SJeremy L. Thompson **/
10902b730f8bSJeremy L Thompson int CeedErrorImpl(Ceed ceed, const char *filename, int lineno, const char *func, int ecode, const char *format, ...) {
10917a982d89SJeremy L. Thompson   va_list args;
1092d1d35e2fSjeremylt   int     ret_val;
10937a982d89SJeremy L. Thompson   va_start(args, format);
10947a982d89SJeremy L. Thompson   if (ceed) {
1095d1d35e2fSjeremylt     ret_val = ceed->Error(ceed, filename, lineno, func, ecode, format, &args);
10967a982d89SJeremy L. Thompson   } else {
1097b0d62198Sjeremylt     // LCOV_EXCL_START
1098477729cfSJeremy L Thompson     const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER");
10992b730f8bSJeremy L Thompson     if (!ceed_error_handler) ceed_error_handler = "abort";
11002b730f8bSJeremy L Thompson     if (!strcmp(ceed_error_handler, "return")) ret_val = CeedErrorReturn(ceed, filename, lineno, func, ecode, format, &args);
1101477729cfSJeremy L Thompson     else
1102477729cfSJeremy L Thompson       // This function will not return
1103d1d35e2fSjeremylt       ret_val = CeedErrorAbort(ceed, filename, lineno, func, ecode, format, &args);
11047a982d89SJeremy L. Thompson   }
11057a982d89SJeremy L. Thompson   va_end(args);
1106d1d35e2fSjeremylt   return ret_val;
1107b0d62198Sjeremylt   // LCOV_EXCL_STOP
11087a982d89SJeremy L. Thompson }
11097a982d89SJeremy L. Thompson 
1110477729cfSJeremy L Thompson /**
1111477729cfSJeremy L Thompson   @brief Error handler that returns without printing anything.
1112477729cfSJeremy L Thompson 
1113477729cfSJeremy L Thompson   Pass this to CeedSetErrorHandler() to obtain this error handling behavior.
1114477729cfSJeremy L Thompson 
1115477729cfSJeremy L Thompson   @ref Developer
1116477729cfSJeremy L Thompson **/
1117477729cfSJeremy L Thompson // LCOV_EXCL_START
11182b730f8bSJeremy L Thompson int CeedErrorReturn(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) {
1119d1d35e2fSjeremylt   return err_code;
1120477729cfSJeremy L Thompson }
1121477729cfSJeremy L Thompson // LCOV_EXCL_STOP
1122477729cfSJeremy L Thompson 
1123477729cfSJeremy L Thompson /**
1124ea61e9acSJeremy L Thompson   @brief Error handler that stores the error message for future use and returns the error.
1125477729cfSJeremy L Thompson 
1126477729cfSJeremy L Thompson   Pass this to CeedSetErrorHandler() to obtain this error handling behavior.
1127477729cfSJeremy L Thompson 
1128477729cfSJeremy L Thompson   @ref Developer
1129477729cfSJeremy L Thompson **/
1130477729cfSJeremy L Thompson // LCOV_EXCL_START
11312b730f8bSJeremy L Thompson int CeedErrorStore(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) {
11322b730f8bSJeremy L Thompson   if (ceed->parent) return CeedErrorStore(ceed->parent, filename, line_no, func, err_code, format, args);
11332b730f8bSJeremy L Thompson   if (ceed->op_fallback_parent) return CeedErrorStore(ceed->op_fallback_parent, filename, line_no, func, err_code, format, args);
1134477729cfSJeremy L Thompson 
1135477729cfSJeremy L Thompson   // Build message
1136990fdeb6SJeremy L Thompson   int len;
11372b730f8bSJeremy L Thompson   len = snprintf(ceed->err_msg, CEED_MAX_RESOURCE_LEN, "%s:%d in %s(): ", filename, line_no, func);
113878464608Sjeremylt   // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized
113978464608Sjeremylt   vsnprintf(ceed->err_msg + len, CEED_MAX_RESOURCE_LEN - len, format, *args);  // NOLINT
1140d1d35e2fSjeremylt   return err_code;
1141477729cfSJeremy L Thompson }
1142477729cfSJeremy L Thompson // LCOV_EXCL_STOP
1143477729cfSJeremy L Thompson 
1144477729cfSJeremy L Thompson /**
1145477729cfSJeremy L Thompson   @brief Error handler that prints to stderr and aborts
1146477729cfSJeremy L Thompson 
1147477729cfSJeremy L Thompson   Pass this to CeedSetErrorHandler() to obtain this error handling behavior.
1148477729cfSJeremy L Thompson 
1149477729cfSJeremy L Thompson   @ref Developer
1150477729cfSJeremy L Thompson **/
1151477729cfSJeremy L Thompson // LCOV_EXCL_START
11522b730f8bSJeremy L Thompson int CeedErrorAbort(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) {
1153d1d35e2fSjeremylt   fprintf(stderr, "%s:%d in %s(): ", filename, line_no, func);
1154f9982c62SWill Pazner   vfprintf(stderr, format, *args);
1155477729cfSJeremy L Thompson   fprintf(stderr, "\n");
1156477729cfSJeremy L Thompson   abort();
1157d1d35e2fSjeremylt   return err_code;
1158477729cfSJeremy L Thompson }
1159477729cfSJeremy L Thompson // LCOV_EXCL_STOP
1160477729cfSJeremy L Thompson 
1161477729cfSJeremy L Thompson /**
1162477729cfSJeremy L Thompson   @brief Error handler that prints to stderr and exits
1163477729cfSJeremy L Thompson 
1164477729cfSJeremy L Thompson   Pass this to CeedSetErrorHandler() to obtain this error handling behavior.
1165477729cfSJeremy L Thompson 
1166ea61e9acSJeremy L Thompson   In contrast to CeedErrorAbort(), this exits without a signal, so atexit() handlers (e.g., as used by gcov) are run.
1167477729cfSJeremy L Thompson 
1168477729cfSJeremy L Thompson   @ref Developer
1169477729cfSJeremy L Thompson **/
11702b730f8bSJeremy L Thompson int CeedErrorExit(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) {
1171d1d35e2fSjeremylt   fprintf(stderr, "%s:%d in %s(): ", filename, line_no, func);
117278464608Sjeremylt   // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized
117378464608Sjeremylt   vfprintf(stderr, format, *args);  // NOLINT
1174477729cfSJeremy L Thompson   fprintf(stderr, "\n");
1175d1d35e2fSjeremylt   exit(err_code);
1176d1d35e2fSjeremylt   return err_code;
1177477729cfSJeremy L Thompson }
1178477729cfSJeremy L Thompson 
1179477729cfSJeremy L Thompson /**
1180477729cfSJeremy L Thompson   @brief Set error handler
1181477729cfSJeremy L Thompson 
1182ea61e9acSJeremy L Thompson   A default error handler is set in CeedInit().
1183ea61e9acSJeremy L Thompson   Use this function to change the error handler to CeedErrorReturn(), CeedErrorAbort(), or a user-defined error handler.
1184477729cfSJeremy L Thompson 
1185477729cfSJeremy L Thompson   @ref Developer
1186477729cfSJeremy L Thompson **/
1187d1d35e2fSjeremylt int CeedSetErrorHandler(Ceed ceed, CeedErrorHandler handler) {
1188d1d35e2fSjeremylt   ceed->Error = handler;
1189d1d35e2fSjeremylt   if (ceed->delegate) CeedSetErrorHandler(ceed->delegate, handler);
11902b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < ceed->obj_delegate_count; i++) CeedSetErrorHandler(ceed->obj_delegates[i].delegate, handler);
1191e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1192477729cfSJeremy L Thompson }
1193477729cfSJeremy L Thompson 
1194477729cfSJeremy L Thompson /**
1195477729cfSJeremy L Thompson   @brief Get error message
1196477729cfSJeremy L Thompson 
1197ea61e9acSJeremy L Thompson   The error message is only stored when using the error handler CeedErrorStore()
1198477729cfSJeremy L Thompson 
1199ea61e9acSJeremy L Thompson   @param[in]  ceed    Ceed context to retrieve error message
1200d1d35e2fSjeremylt   @param[out] err_msg Char pointer to hold error message
1201477729cfSJeremy L Thompson 
1202477729cfSJeremy L Thompson   @ref Developer
1203477729cfSJeremy L Thompson **/
1204d1d35e2fSjeremylt int CeedGetErrorMessage(Ceed ceed, const char **err_msg) {
12052b730f8bSJeremy L Thompson   if (ceed->parent) return CeedGetErrorMessage(ceed->parent, err_msg);
12062b730f8bSJeremy L Thompson   if (ceed->op_fallback_parent) 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 
1214ea61e9acSJeremy L Thompson   The error message is only stored when using the error handler CeedErrorStore()
1215477729cfSJeremy L Thompson 
1216ea61e9acSJeremy L Thompson   @param[in]  ceed    Ceed context to restore error message
1217d1d35e2fSjeremylt   @param[out] err_msg Char pointer that holds error message
1218477729cfSJeremy L Thompson 
1219477729cfSJeremy L Thompson   @ref Developer
1220477729cfSJeremy L Thompson **/
1221d1d35e2fSjeremylt int CeedResetErrorMessage(Ceed ceed, const char **err_msg) {
12222b730f8bSJeremy L Thompson   if (ceed->parent) return CeedResetErrorMessage(ceed->parent, err_msg);
12232b730f8bSJeremy L Thompson   if (ceed->op_fallback_parent) return CeedResetErrorMessage(ceed->op_fallback_parent, err_msg);
1224d1d35e2fSjeremylt   *err_msg = NULL;
1225d1d35e2fSjeremylt   memcpy(ceed->err_msg, "No error message stored", 24);
1226e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1227477729cfSJeremy L Thompson }
1228477729cfSJeremy L Thompson 
12291070991dSJed Brown /**
12301070991dSJed Brown   @brief Get libCEED library version info
12311070991dSJed Brown 
1232ea61e9acSJeremy L Thompson   libCEED version numbers have the form major.minor.patch.
1233ea61e9acSJeremy L Thompson   Non-release versions may contain unstable interfaces.
12341070991dSJed Brown 
12351070991dSJed Brown   @param[out] major   Major version of the library
12361070991dSJed Brown   @param[out] minor   Minor version of the library
12371070991dSJed Brown   @param[out] patch   Patch (subminor) version of the library
12381070991dSJed Brown   @param[out] release True for releases; false for development branches.
12391070991dSJed Brown 
12401070991dSJed Brown   The caller may pass NULL for any arguments that are not needed.
12411070991dSJed Brown 
12421070991dSJed Brown   @sa CEED_VERSION_GE()
12431070991dSJed Brown 
12441070991dSJed Brown   @ref Developer
12451070991dSJed Brown */
12461070991dSJed Brown int CeedGetVersion(int *major, int *minor, int *patch, bool *release) {
12471070991dSJed Brown   if (major) *major = CEED_VERSION_MAJOR;
12481070991dSJed Brown   if (minor) *minor = CEED_VERSION_MINOR;
12491070991dSJed Brown   if (patch) *patch = CEED_VERSION_PATCH;
12501070991dSJed Brown   if (release) *release = CEED_VERSION_RELEASE;
12511070991dSJed Brown   return 0;
12521070991dSJed Brown }
12531070991dSJed Brown 
125480a9ef05SNatalie Beams int CeedGetScalarType(CeedScalarType *scalar_type) {
125580a9ef05SNatalie Beams   *scalar_type = CEED_SCALAR_TYPE;
125680a9ef05SNatalie Beams   return 0;
125780a9ef05SNatalie Beams }
125880a9ef05SNatalie Beams 
1259d7b241e6Sjeremylt /// @}
1260