xref: /libCEED/interface/ceed.c (revision 6574a04ff2135c3834f1b6ef9a4ec7566c4782db)
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.
1136a406739SJeremy L Thompson            Note: Backends should call `CeedRegister` instead.
1146a406739SJeremy L Thompson 
115ea61e9acSJeremy L Thompson   @param[in] prefix    Prefix of resources for this backend to respond to.
116ea61e9acSJeremy L Thompson                          For example, the reference backend responds to "/cpu/self".
117ea61e9acSJeremy L Thompson   @param[in] init      Initialization function called by CeedInit() when the backend is selected to drive the requested resource.
118ea61e9acSJeremy L Thompson   @param[in] priority  Integer priority.
119ea61e9acSJeremy L Thompson                          Lower values are preferred in case the resource requested by CeedInit() has non-unique best prefix match.
1206a406739SJeremy L Thompson 
1216a406739SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1226a406739SJeremy L Thompson 
1236a406739SJeremy L Thompson   @ref Developer
1246a406739SJeremy L Thompson **/
1252b730f8bSJeremy L Thompson int CeedRegisterImpl(const char *prefix, int (*init)(const char *, Ceed), unsigned int priority) {
126*6574a04fSJeremy L Thompson   CeedCheck(num_backends < sizeof(backends) / sizeof(backends[0]), NULL, CEED_ERROR_MAJOR, "Too many backends");
1276a406739SJeremy L Thompson 
1286a406739SJeremy L Thompson   strncpy(backends[num_backends].prefix, prefix, CEED_MAX_RESOURCE_LEN);
1296a406739SJeremy L Thompson   backends[num_backends].prefix[CEED_MAX_RESOURCE_LEN - 1] = 0;
1306a406739SJeremy L Thompson   backends[num_backends].init                              = init;
1316a406739SJeremy L Thompson   backends[num_backends].priority                          = priority;
1326a406739SJeremy L Thompson   num_backends++;
1336a406739SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1346a406739SJeremy L Thompson }
1356a406739SJeremy L Thompson 
1367a982d89SJeremy L. Thompson /// @}
137d7b241e6Sjeremylt 
1387a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
1397a982d89SJeremy L. Thompson /// Ceed Backend API
1407a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
1417a982d89SJeremy L. Thompson /// @addtogroup CeedBackend
1427a982d89SJeremy L. Thompson /// @{
143d7b241e6Sjeremylt 
144b11c1e72Sjeremylt /**
1453f21f6b1SJeremy L Thompson   @brief Return value of CEED_DEBUG environment variable
14660f9e2d6SJeremy L Thompson 
147ea61e9acSJeremy L Thompson   @param[in] ceed Ceed context
14860f9e2d6SJeremy L Thompson 
1493f21f6b1SJeremy L Thompson   @return boolean value: true  - debugging mode enabled
1503f21f6b1SJeremy L Thompson                          false - debugging mode disabled
15160f9e2d6SJeremy L Thompson 
15260f9e2d6SJeremy L Thompson   @ref Backend
15360f9e2d6SJeremy L Thompson **/
154fc6bbcedSJeremy L Thompson // LCOV_EXCL_START
1552b730f8bSJeremy L Thompson bool CeedDebugFlag(const Ceed ceed) { return ceed->is_debug; }
156fc6bbcedSJeremy L Thompson // LCOV_EXCL_STOP
15760f9e2d6SJeremy L Thompson 
15860f9e2d6SJeremy L Thompson /**
1593f21f6b1SJeremy L Thompson   @brief Return value of CEED_DEBUG environment variable
16060f9e2d6SJeremy L Thompson 
1613f21f6b1SJeremy L Thompson   @return boolean value: true  - debugging mode enabled
1623f21f6b1SJeremy L Thompson                          false - debugging mode disabled
1633f21f6b1SJeremy L Thompson 
1643f21f6b1SJeremy L Thompson   @ref Backend
1653f21f6b1SJeremy L Thompson **/
1663f21f6b1SJeremy L Thompson // LCOV_EXCL_START
1672b730f8bSJeremy L Thompson bool CeedDebugFlagEnv(void) { return !!getenv("CEED_DEBUG") || !!getenv("DEBUG") || !!getenv("DBG"); }
1683f21f6b1SJeremy L Thompson // LCOV_EXCL_STOP
1693f21f6b1SJeremy L Thompson 
1703f21f6b1SJeremy L Thompson /**
1713f21f6b1SJeremy L Thompson   @brief Print debugging information in color
1723f21f6b1SJeremy L Thompson 
17360f9e2d6SJeremy L Thompson   @param color   Color to print
17460f9e2d6SJeremy L Thompson   @param format  Printing format
17560f9e2d6SJeremy L Thompson 
17660f9e2d6SJeremy L Thompson   @ref Backend
17760f9e2d6SJeremy L Thompson **/
178fc6bbcedSJeremy L Thompson // LCOV_EXCL_START
1793f21f6b1SJeremy L Thompson void CeedDebugImpl256(const unsigned char color, const char *format, ...) {
18060f9e2d6SJeremy L Thompson   va_list args;
18160f9e2d6SJeremy L Thompson   va_start(args, format);
18260f9e2d6SJeremy L Thompson   fflush(stdout);
1832b730f8bSJeremy L Thompson   if (color != CEED_DEBUG_COLOR_NONE) fprintf(stdout, "\033[38;5;%dm", color);
18460f9e2d6SJeremy L Thompson   vfprintf(stdout, format, args);
1852b730f8bSJeremy L Thompson   if (color != CEED_DEBUG_COLOR_NONE) fprintf(stdout, "\033[m");
18660f9e2d6SJeremy L Thompson   fprintf(stdout, "\n");
18760f9e2d6SJeremy L Thompson   fflush(stdout);
18860f9e2d6SJeremy L Thompson   va_end(args);
18960f9e2d6SJeremy L Thompson }
190fc6bbcedSJeremy L Thompson // LCOV_EXCL_STOP
19160f9e2d6SJeremy L Thompson 
19260f9e2d6SJeremy L Thompson /**
193b11c1e72Sjeremylt   @brief Allocate an array on the host; use CeedMalloc()
194b11c1e72Sjeremylt 
195ea61e9acSJeremy L Thompson   Memory usage can be tracked by the library.
196ea61e9acSJeremy L Thompson   This ensures sufficient alignment for vectorization and should be used for large allocations.
197b11c1e72Sjeremylt 
198ea61e9acSJeremy L Thompson   @param[in]  n    Number of units to allocate
199ea61e9acSJeremy L Thompson   @param[in]  unit Size of each unit
200ea61e9acSJeremy L Thompson   @param[out] p    Address of pointer to hold the result.
201b11c1e72Sjeremylt 
202b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
203b11c1e72Sjeremylt 
204b11c1e72Sjeremylt   @sa CeedFree()
205dfdf5a53Sjeremylt 
2067a982d89SJeremy L. Thompson   @ref Backend
207b11c1e72Sjeremylt **/
208d7b241e6Sjeremylt int CeedMallocArray(size_t n, size_t unit, void *p) {
209d7b241e6Sjeremylt   int ierr = posix_memalign((void **)p, CEED_ALIGN, n * unit);
210*6574a04fSJeremy L Thompson   CeedCheck(ierr == 0, NULL, CEED_ERROR_MAJOR, "posix_memalign failed to allocate %zd members of size %zd\n", n, unit);
211e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
212d7b241e6Sjeremylt }
213d7b241e6Sjeremylt 
214b11c1e72Sjeremylt /**
215b11c1e72Sjeremylt   @brief Allocate a cleared (zeroed) array on the host; use CeedCalloc()
216b11c1e72Sjeremylt 
217b11c1e72Sjeremylt   Memory usage can be tracked by the library.
218b11c1e72Sjeremylt 
219ea61e9acSJeremy L Thompson   @param[in]  n    Number of units to allocate
220ea61e9acSJeremy L Thompson   @param[in]  unit Size of each unit
221ea61e9acSJeremy L Thompson   @param[out] p    Address of pointer to hold the result.
222b11c1e72Sjeremylt 
223b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
224b11c1e72Sjeremylt 
225b11c1e72Sjeremylt   @sa CeedFree()
226dfdf5a53Sjeremylt 
2277a982d89SJeremy L. Thompson   @ref Backend
228b11c1e72Sjeremylt **/
229d7b241e6Sjeremylt int CeedCallocArray(size_t n, size_t unit, void *p) {
230d7b241e6Sjeremylt   *(void **)p = calloc(n, unit);
231*6574a04fSJeremy L Thompson   CeedCheck(!n || !unit || *(void **)p, NULL, CEED_ERROR_MAJOR, "calloc failed to allocate %zd members of size %zd\n", n, unit);
232e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
233d7b241e6Sjeremylt }
234d7b241e6Sjeremylt 
235b11c1e72Sjeremylt /**
236b11c1e72Sjeremylt   @brief Reallocate an array on the host; use CeedRealloc()
237b11c1e72Sjeremylt 
238b11c1e72Sjeremylt   Memory usage can be tracked by the library.
239b11c1e72Sjeremylt 
240ea61e9acSJeremy L Thompson   @param[in]  n    Number of units to allocate
241ea61e9acSJeremy L Thompson   @param[in]  unit Size of each unit
242ea61e9acSJeremy L Thompson   @param[out] p    Address of pointer to hold the result.
243b11c1e72Sjeremylt 
244b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
245b11c1e72Sjeremylt 
246b11c1e72Sjeremylt   @sa CeedFree()
247dfdf5a53Sjeremylt 
2487a982d89SJeremy L. Thompson   @ref Backend
249b11c1e72Sjeremylt **/
250d7b241e6Sjeremylt int CeedReallocArray(size_t n, size_t unit, void *p) {
251d7b241e6Sjeremylt   *(void **)p = realloc(*(void **)p, n * unit);
252*6574a04fSJeremy L Thompson   CeedCheck(!n || !unit || *(void **)p, NULL, CEED_ERROR_MAJOR, "realloc failed to allocate %zd members of size %zd\n", n, unit);
253e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
254d7b241e6Sjeremylt }
255d7b241e6Sjeremylt 
256f7e22acaSJeremy L Thompson /**
257f7e22acaSJeremy L Thompson   @brief Allocate a cleared string buffer on the host
258f7e22acaSJeremy L Thompson 
259f7e22acaSJeremy L Thompson   Memory usage can be tracked by the library.
260f7e22acaSJeremy L Thompson 
261ea61e9acSJeremy L Thompson   @param[in]  source Pointer to string to be copied
262ea61e9acSJeremy L Thompson   @param[out] copy   Pointer to variable to hold newly allocated string copy
263f7e22acaSJeremy L Thompson 
264f7e22acaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
265f7e22acaSJeremy L Thompson 
266f7e22acaSJeremy L Thompson   @sa CeedFree()
267f7e22acaSJeremy L Thompson 
268f7e22acaSJeremy L Thompson   @ref Backend
269f7e22acaSJeremy L Thompson **/
270f7e22acaSJeremy L Thompson int CeedStringAllocCopy(const char *source, char **copy) {
271f7e22acaSJeremy L Thompson   size_t len = strlen(source);
2722b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(len + 1, copy));
273d602d780SJeremy L Thompson   memcpy(*copy, source, len);
274f7e22acaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
275f7e22acaSJeremy L Thompson }
276f7e22acaSJeremy L Thompson 
27734138859Sjeremylt /** Free memory allocated using CeedMalloc() or CeedCalloc()
27834138859Sjeremylt 
279ea61e9acSJeremy L Thompson   @param[in,out] p  address of pointer to memory.
280ea61e9acSJeremy 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
281ea61e9acSJeremy L Thompson pointer.
28234138859Sjeremylt **/
283d7b241e6Sjeremylt int CeedFree(void *p) {
284d7b241e6Sjeremylt   free(*(void **)p);
285d7b241e6Sjeremylt   *(void **)p = NULL;
286e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
287d7b241e6Sjeremylt }
288d7b241e6Sjeremylt 
289d7b241e6Sjeremylt /**
2907a982d89SJeremy L. Thompson   @brief Register a Ceed backend
291d7b241e6Sjeremylt 
292ea61e9acSJeremy L Thompson   @param[in] prefix   Prefix of resources for this backend to respond to.
293ea61e9acSJeremy L Thompson                         For example, the reference backend responds to "/cpu/self".
294ea61e9acSJeremy L Thompson   @param[in] init     Initialization function called by CeedInit() when the backend is selected to drive the requested resource.
295ea61e9acSJeremy L Thompson   @param[in] priority Integer priority.
296ea61e9acSJeremy L Thompson                         Lower values are preferred in case the resource requested by CeedInit() has non-unique best prefix match.
297b11c1e72Sjeremylt 
298b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
299dfdf5a53Sjeremylt 
3007a982d89SJeremy L. Thompson   @ref Backend
301b11c1e72Sjeremylt **/
3022b730f8bSJeremy L Thompson int CeedRegister(const char *prefix, int (*init)(const char *, Ceed), unsigned int priority) {
30310243053SJeremy L Thompson   CeedDebugEnv("Backend Register: %s", prefix);
3046a406739SJeremy L Thompson   CeedRegisterImpl(prefix, init, priority);
305e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
306d7b241e6Sjeremylt }
307d7b241e6Sjeremylt 
308b11c1e72Sjeremylt /**
30960f9e2d6SJeremy L Thompson   @brief Return debugging status flag
31060f9e2d6SJeremy L Thompson 
311ea61e9acSJeremy L Thompson   @param[in]  ceed     Ceed context to get debugging flag
312ea61e9acSJeremy L Thompson   @param[out] is_debug Variable to store debugging flag
31360f9e2d6SJeremy L Thompson 
31460f9e2d6SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
31560f9e2d6SJeremy L Thompson 
316d1d35e2fSjeremylt   @ref Backend
31760f9e2d6SJeremy L Thompson **/
318d1d35e2fSjeremylt int CeedIsDebug(Ceed ceed, bool *is_debug) {
3193f21f6b1SJeremy L Thompson   *is_debug = ceed->is_debug;
320e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
32160f9e2d6SJeremy L Thompson }
32260f9e2d6SJeremy L Thompson 
32360f9e2d6SJeremy L Thompson /**
3247a982d89SJeremy L. Thompson   @brief Retrieve a parent Ceed context
3257a982d89SJeremy L. Thompson 
326ea61e9acSJeremy L Thompson   @param[in]  ceed   Ceed context to retrieve parent of
3277a982d89SJeremy L. Thompson   @param[out] parent Address to save the parent to
3287a982d89SJeremy L. Thompson 
3297a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3307a982d89SJeremy L. Thompson 
3317a982d89SJeremy L. Thompson   @ref Backend
3327a982d89SJeremy L. Thompson **/
3337a982d89SJeremy L. Thompson int CeedGetParent(Ceed ceed, Ceed *parent) {
3347a982d89SJeremy L. Thompson   if (ceed->parent) {
3352b730f8bSJeremy L Thompson     CeedCall(CeedGetParent(ceed->parent, parent));
336e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
3377a982d89SJeremy L. Thompson   }
3387a982d89SJeremy L. Thompson   *parent = ceed;
339e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3407a982d89SJeremy L. Thompson }
3417a982d89SJeremy L. Thompson 
3427a982d89SJeremy L. Thompson /**
3437a982d89SJeremy L. Thompson   @brief Retrieve a delegate Ceed context
3447a982d89SJeremy L. Thompson 
345ea61e9acSJeremy L Thompson   @param[in]  ceed     Ceed context to retrieve delegate of
3467a982d89SJeremy L. Thompson   @param[out] delegate Address to save the delegate to
3477a982d89SJeremy L. Thompson 
3487a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3497a982d89SJeremy L. Thompson 
3507a982d89SJeremy L. Thompson   @ref Backend
3517a982d89SJeremy L. Thompson **/
3527a982d89SJeremy L. Thompson int CeedGetDelegate(Ceed ceed, Ceed *delegate) {
3537a982d89SJeremy L. Thompson   *delegate = ceed->delegate;
354e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3557a982d89SJeremy L. Thompson }
3567a982d89SJeremy L. Thompson 
3577a982d89SJeremy L. Thompson /**
3587a982d89SJeremy L. Thompson   @brief Set a delegate Ceed context
3597a982d89SJeremy L. Thompson 
360ea61e9acSJeremy L Thompson   This function allows a Ceed context to set a delegate Ceed context.
361ea61e9acSJeremy L Thompson     All backend implementations default to the delegate Ceed context, unless overridden.
3627a982d89SJeremy L. Thompson 
363ea61e9acSJeremy L Thompson   @param[in]  ceed     Ceed context to set delegate of
3647a982d89SJeremy L. Thompson   @param[out] delegate Address to set the delegate to
3657a982d89SJeremy L. Thompson 
3667a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3677a982d89SJeremy L. Thompson 
3687a982d89SJeremy L. Thompson   @ref Backend
3697a982d89SJeremy L. Thompson **/
3707a982d89SJeremy L. Thompson int CeedSetDelegate(Ceed ceed, Ceed delegate) {
3717a982d89SJeremy L. Thompson   ceed->delegate   = delegate;
3727a982d89SJeremy L. Thompson   delegate->parent = ceed;
373e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3747a982d89SJeremy L. Thompson }
3757a982d89SJeremy L. Thompson 
3767a982d89SJeremy L. Thompson /**
3777a982d89SJeremy L. Thompson   @brief Retrieve a delegate Ceed context for a specific object type
3787a982d89SJeremy L. Thompson 
379ea61e9acSJeremy L Thompson   @param[in]  ceed     Ceed context to retrieve delegate of
3807a982d89SJeremy L. Thompson   @param[out] delegate Address to save the delegate to
381d1d35e2fSjeremylt   @param[in]  obj_name Name of the object type to retrieve delegate for
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 **/
387d1d35e2fSjeremylt int CeedGetObjectDelegate(Ceed ceed, Ceed *delegate, const char *obj_name) {
3887a982d89SJeremy L. Thompson   // Check for object delegate
3892b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < ceed->obj_delegate_count; i++) {
390d1d35e2fSjeremylt     if (!strcmp(obj_name, ceed->obj_delegates->obj_name)) {
391d1d35e2fSjeremylt       *delegate = ceed->obj_delegates->delegate;
392e15f9bd0SJeremy L Thompson       return CEED_ERROR_SUCCESS;
3937a982d89SJeremy L. Thompson     }
3942b730f8bSJeremy L Thompson   }
3957a982d89SJeremy L. Thompson 
3967a982d89SJeremy L. Thompson   // Use default delegate if no object delegate
3972b730f8bSJeremy L Thompson   CeedCall(CeedGetDelegate(ceed, delegate));
398e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3997a982d89SJeremy L. Thompson }
4007a982d89SJeremy L. Thompson 
4017a982d89SJeremy L. Thompson /**
4027a982d89SJeremy L. Thompson   @brief Set a delegate Ceed context for a specific object type
4037a982d89SJeremy L. Thompson 
404ea61e9acSJeremy L Thompson   This function allows a Ceed context to set a delegate Ceed context for a given type of Ceed object.
405ea61e9acSJeremy L Thompson     All backend implementations default to the delegate Ceed context for this object.
406ea61e9acSJeremy L Thompson     For example, CeedSetObjectDelegate(ceed, refceed, "Basis") uses refceed implementations for all CeedBasis backend functions.
4077a982d89SJeremy L. Thompson 
408ea61e9acSJeremy L Thompson   @param[in,out] ceed     Ceed context to set delegate of
4097a982d89SJeremy L. Thompson   @param[out]    delegate Address to set the delegate to
410d1d35e2fSjeremylt   @param[in]     obj_name Name of the object type to set delegate for
4117a982d89SJeremy L. Thompson 
4127a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4137a982d89SJeremy L. Thompson 
4147a982d89SJeremy L. Thompson   @ref Backend
4157a982d89SJeremy L. Thompson **/
416d1d35e2fSjeremylt int CeedSetObjectDelegate(Ceed ceed, Ceed delegate, const char *obj_name) {
417d1d35e2fSjeremylt   CeedInt count = ceed->obj_delegate_count;
4187a982d89SJeremy L. Thompson 
4197a982d89SJeremy L. Thompson   // Malloc or Realloc
4207a982d89SJeremy L. Thompson   if (count) {
4212b730f8bSJeremy L Thompson     CeedCall(CeedRealloc(count + 1, &ceed->obj_delegates));
4227a982d89SJeremy L. Thompson   } else {
4232b730f8bSJeremy L Thompson     CeedCall(CeedCalloc(1, &ceed->obj_delegates));
4247a982d89SJeremy L. Thompson   }
425d1d35e2fSjeremylt   ceed->obj_delegate_count++;
4267a982d89SJeremy L. Thompson 
4277a982d89SJeremy L. Thompson   // Set object delegate
428d1d35e2fSjeremylt   ceed->obj_delegates[count].delegate = delegate;
4292b730f8bSJeremy L Thompson   CeedCall(CeedStringAllocCopy(obj_name, &ceed->obj_delegates[count].obj_name));
4307a982d89SJeremy L. Thompson 
4317a982d89SJeremy L. Thompson   // Set delegate parent
4327a982d89SJeremy L. Thompson   delegate->parent = ceed;
433e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4347a982d89SJeremy L. Thompson }
4357a982d89SJeremy L. Thompson 
4367a982d89SJeremy L. Thompson /**
4377a982d89SJeremy L. Thompson   @brief Get the fallback resource for CeedOperators
4387a982d89SJeremy L. Thompson 
439ea61e9acSJeremy L Thompson   @param[in]  ceed     Ceed context
4407a982d89SJeremy L. Thompson   @param[out] resource Variable to store fallback resource
4417a982d89SJeremy L. Thompson 
4427a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4437a982d89SJeremy L. Thompson 
4447a982d89SJeremy L. Thompson   @ref Backend
4457a982d89SJeremy L. Thompson **/
4467a982d89SJeremy L. Thompson 
4477a982d89SJeremy L. Thompson int CeedGetOperatorFallbackResource(Ceed ceed, const char **resource) {
448d1d35e2fSjeremylt   *resource = (const char *)ceed->op_fallback_resource;
449e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4507a982d89SJeremy L. Thompson }
4517a982d89SJeremy L. Thompson 
4527a982d89SJeremy L. Thompson /**
4538687e1d4SJeremy L Thompson   @brief Get the fallback Ceed for CeedOperators
4548687e1d4SJeremy L Thompson 
455ea61e9acSJeremy L Thompson   @param[in]  ceed          Ceed context
4568687e1d4SJeremy L Thompson   @param[out] fallback_ceed Variable to store fallback Ceed
4578687e1d4SJeremy L Thompson 
4588687e1d4SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
4598687e1d4SJeremy L Thompson 
4608687e1d4SJeremy L Thompson   @ref Backend
4618687e1d4SJeremy L Thompson **/
4628687e1d4SJeremy L Thompson 
4638687e1d4SJeremy L Thompson int CeedGetOperatorFallbackCeed(Ceed ceed, Ceed *fallback_ceed) {
464d04bbc78SJeremy L Thompson   if (ceed->has_valid_op_fallback_resource) {
465d04bbc78SJeremy L Thompson     CeedDebug256(ceed, 1, "---------- CeedOperator Fallback ----------\n");
4662b730f8bSJeremy L Thompson     CeedDebug(ceed, "Getting fallback from %s to %s\n", ceed->resource, ceed->op_fallback_resource);
467d04bbc78SJeremy L Thompson   }
4688687e1d4SJeremy L Thompson 
469d04bbc78SJeremy L Thompson   // Create fallback Ceed if uninitalized
470d04bbc78SJeremy L Thompson   if (!ceed->op_fallback_ceed && ceed->has_valid_op_fallback_resource) {
47113f886e9SJeremy L Thompson     CeedDebug(ceed, "Creating fallback Ceed");
472d04bbc78SJeremy L Thompson 
4738687e1d4SJeremy L Thompson     Ceed        fallback_ceed;
474d04bbc78SJeremy L Thompson     const char *fallback_resource;
475d04bbc78SJeremy L Thompson 
4762b730f8bSJeremy L Thompson     CeedCall(CeedGetOperatorFallbackResource(ceed, &fallback_resource));
4772b730f8bSJeremy L Thompson     CeedCall(CeedInit(fallback_resource, &fallback_ceed));
4788687e1d4SJeremy L Thompson     fallback_ceed->op_fallback_parent = ceed;
4798687e1d4SJeremy L Thompson     fallback_ceed->Error              = ceed->Error;
4808687e1d4SJeremy L Thompson     ceed->op_fallback_ceed            = fallback_ceed;
4818687e1d4SJeremy L Thompson   }
4828687e1d4SJeremy L Thompson   *fallback_ceed = ceed->op_fallback_ceed;
4838687e1d4SJeremy L Thompson 
4848687e1d4SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4858687e1d4SJeremy L Thompson }
4868687e1d4SJeremy L Thompson 
4878687e1d4SJeremy L Thompson /**
488ea61e9acSJeremy L Thompson   @brief Set the fallback resource for CeedOperators.
489ea61e9acSJeremy L Thompson            The current resource, if any, is freed by calling this function.
490ea61e9acSJeremy L Thompson            This string is freed upon the destruction of the Ceed context.
4917a982d89SJeremy L. Thompson 
492ea61e9acSJeremy L Thompson   @param[in,out] ceed     Ceed context
493ea61e9acSJeremy L Thompson   @param[in]     resource Fallback resource to set
4947a982d89SJeremy L. Thompson 
4957a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4967a982d89SJeremy L. Thompson 
4977a982d89SJeremy L. Thompson   @ref Backend
4987a982d89SJeremy L. Thompson **/
4997a982d89SJeremy L. Thompson 
5007a982d89SJeremy L. Thompson int CeedSetOperatorFallbackResource(Ceed ceed, const char *resource) {
5017a982d89SJeremy L. Thompson   // Free old
5022b730f8bSJeremy L Thompson   CeedCall(CeedFree(&ceed->op_fallback_resource));
5037a982d89SJeremy L. Thompson 
5047a982d89SJeremy L. Thompson   // Set new
5052b730f8bSJeremy L Thompson   CeedCall(CeedStringAllocCopy(resource, (char **)&ceed->op_fallback_resource));
506d04bbc78SJeremy L Thompson 
507d04bbc78SJeremy L Thompson   // Check validity
5082b730f8bSJeremy L Thompson   ceed->has_valid_op_fallback_resource = ceed->op_fallback_resource && ceed->resource && strcmp(ceed->op_fallback_resource, ceed->resource);
509d04bbc78SJeremy L Thompson 
510e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5117a982d89SJeremy L. Thompson }
5127a982d89SJeremy L. Thompson 
5137a982d89SJeremy L. Thompson /**
514ea61e9acSJeremy L Thompson   @brief Get the parent Ceed context associated with a fallback Ceed context for a CeedOperator
5157a982d89SJeremy L. Thompson 
516ea61e9acSJeremy L Thompson   @param[in]  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 
532ea61e9acSJeremy L Thompson   @param[in]  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 
548ea61e9acSJeremy L Thompson   This function is used for a backend to set the function associated with the Ceed objects.
549ea61e9acSJeremy L Thompson     For example, CeedSetBackendFunction(ceed, "Ceed", ceed, "VectorCreate", BackendVectorCreate) sets the backend implementation of 'CeedVectorCreate'
550ea61e9acSJeremy L Thompson and CeedSetBackendFunction(ceed, "Basis", basis, "Apply", BackendBasisApply) sets the backend implementation of 'CeedBasisApply'. Note, the prefix
551ea61e9acSJeremy L Thompson 'Ceed' is not required for the object type ("Basis" vs "CeedBasis").
5527a982d89SJeremy L. Thompson 
553ea61e9acSJeremy L Thompson   @param[in]  ceed      Ceed context for error handling
554ea61e9acSJeremy L Thompson   @param[in]  type      Type of Ceed object to set function for
5557a982d89SJeremy L. Thompson   @param[out] object    Ceed object to set function for
556ea61e9acSJeremy L Thompson   @param[in]  func_name Name of function to set
557ea61e9acSJeremy L Thompson   @param[in]  f         Function to set
5587a982d89SJeremy L. Thompson 
5597a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5607a982d89SJeremy L. Thompson 
5617a982d89SJeremy L. Thompson   @ref Backend
5627a982d89SJeremy L. Thompson **/
5632b730f8bSJeremy L Thompson int CeedSetBackendFunction(Ceed ceed, const char *type, void *object, const char *func_name, int (*f)()) {
564d1d35e2fSjeremylt   char lookup_name[CEED_MAX_RESOURCE_LEN + 1] = "";
5657a982d89SJeremy L. Thompson 
5667a982d89SJeremy L. Thompson   // Build lookup name
5672b730f8bSJeremy L Thompson   if (strcmp(type, "Ceed")) strncat(lookup_name, "Ceed", CEED_MAX_RESOURCE_LEN);
568d1d35e2fSjeremylt   strncat(lookup_name, type, CEED_MAX_RESOURCE_LEN);
569d1d35e2fSjeremylt   strncat(lookup_name, func_name, CEED_MAX_RESOURCE_LEN);
5707a982d89SJeremy L. Thompson 
5717a982d89SJeremy L. Thompson   // Find and use offset
5722b730f8bSJeremy L Thompson   for (CeedInt i = 0; ceed->f_offsets[i].func_name; i++) {
573d1d35e2fSjeremylt     if (!strcmp(ceed->f_offsets[i].func_name, lookup_name)) {
574d1d35e2fSjeremylt       size_t offset          = ceed->f_offsets[i].offset;
5757a982d89SJeremy L. Thompson       int (**fpointer)(void) = (int (**)(void))((char *)object + offset);  // *NOPAD*
5767a982d89SJeremy L. Thompson       *fpointer              = f;
577e15f9bd0SJeremy L Thompson       return CEED_ERROR_SUCCESS;
5787a982d89SJeremy L. Thompson     }
5792b730f8bSJeremy L Thompson   }
5807a982d89SJeremy L. Thompson 
5817a982d89SJeremy L. Thompson   // LCOV_EXCL_START
5822b730f8bSJeremy L Thompson   return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Requested function '%s' was not found for CEED object '%s'", func_name, type);
5837a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
5847a982d89SJeremy L. Thompson }
5857a982d89SJeremy L. Thompson 
5867a982d89SJeremy L. Thompson /**
5877a982d89SJeremy L. Thompson   @brief Retrieve backend data for a Ceed context
5887a982d89SJeremy L. Thompson 
589ea61e9acSJeremy L Thompson   @param[in]  ceed Ceed context to retrieve data of
5907a982d89SJeremy L. Thompson   @param[out] data Address to save data to
5917a982d89SJeremy L. Thompson 
5927a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5937a982d89SJeremy L. Thompson 
5947a982d89SJeremy L. Thompson   @ref Backend
5957a982d89SJeremy L. Thompson **/
596777ff853SJeremy L Thompson int CeedGetData(Ceed ceed, void *data) {
597777ff853SJeremy L Thompson   *(void **)data = ceed->data;
598e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5997a982d89SJeremy L. Thompson }
6007a982d89SJeremy L. Thompson 
6017a982d89SJeremy L. Thompson /**
6027a982d89SJeremy L. Thompson   @brief Set backend data for a Ceed context
6037a982d89SJeremy L. Thompson 
604ea61e9acSJeremy L Thompson   @param[in,out] ceed Ceed context to set data of
605ea61e9acSJeremy L Thompson   @param[in]     data Address of data to set
6067a982d89SJeremy L. Thompson 
6077a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6087a982d89SJeremy L. Thompson 
6097a982d89SJeremy L. Thompson   @ref Backend
6107a982d89SJeremy L. Thompson **/
611777ff853SJeremy L Thompson int CeedSetData(Ceed ceed, void *data) {
612777ff853SJeremy L Thompson   ceed->data = data;
613e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6147a982d89SJeremy L. Thompson }
6157a982d89SJeremy L. Thompson 
61634359f16Sjeremylt /**
61734359f16Sjeremylt   @brief Increment the reference counter for a Ceed context
61834359f16Sjeremylt 
619ea61e9acSJeremy L Thompson   @param[in,out] ceed Ceed context to increment the reference counter
62034359f16Sjeremylt 
62134359f16Sjeremylt   @return An error code: 0 - success, otherwise - failure
62234359f16Sjeremylt 
62334359f16Sjeremylt   @ref Backend
62434359f16Sjeremylt **/
6259560d06aSjeremylt int CeedReference(Ceed ceed) {
62634359f16Sjeremylt   ceed->ref_count++;
62734359f16Sjeremylt   return CEED_ERROR_SUCCESS;
62834359f16Sjeremylt }
62934359f16Sjeremylt 
6307a982d89SJeremy L. Thompson /// @}
6317a982d89SJeremy L. Thompson 
6327a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
6337a982d89SJeremy L. Thompson /// Ceed Public API
6347a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
6357a982d89SJeremy L. Thompson /// @addtogroup CeedUser
6367a982d89SJeremy L. Thompson /// @{
6377a982d89SJeremy L. Thompson 
6387a982d89SJeremy L. Thompson /**
63992ee7d1cSjeremylt   @brief Get the list of available resource names for Ceed contexts
640ea61e9acSJeremy L Thompson            Note: The caller is responsible for `free()`ing the resources and priorities arrays, but should not `free()` the contents of the resources
641ea61e9acSJeremy L Thompson array.
64222e44211Sjeremylt 
64392ee7d1cSjeremylt   @param[out] n          Number of available resources
64492ee7d1cSjeremylt   @param[out] resources  List of available resource names
64522e44211Sjeremylt   @param[out] priorities Resource name prioritization values, lower is better
64622e44211Sjeremylt 
64722e44211Sjeremylt   @return An error code: 0 - success, otherwise - failure
64822e44211Sjeremylt 
64922e44211Sjeremylt   @ref User
65022e44211Sjeremylt **/
65122e44211Sjeremylt // LCOV_EXCL_START
6522b730f8bSJeremy L Thompson int CeedRegistryGetList(size_t *n, char ***const resources, CeedInt **priorities) {
653d0c91ce9Sjeremylt   *n         = 0;
6549ff86846Sjeremylt   *resources = malloc(num_backends * sizeof(**resources));
655*6574a04fSJeremy L Thompson   CeedCheck(resources, NULL, CEED_ERROR_MAJOR, "malloc() failure");
6569ff86846Sjeremylt   if (priorities) {
6579ff86846Sjeremylt     *priorities = malloc(num_backends * sizeof(**priorities));
658*6574a04fSJeremy L Thompson     CeedCheck(priorities, NULL, CEED_ERROR_MAJOR, "malloc() failure");
6599ff86846Sjeremylt   }
66022e44211Sjeremylt   for (size_t i = 0; i < num_backends; i++) {
661d0c91ce9Sjeremylt     // Only report compiled backends
662d0c91ce9Sjeremylt     if (backends[i].priority < CEED_MAX_BACKEND_PRIORITY) {
66322e44211Sjeremylt       *resources[i] = backends[i].prefix;
6649ff86846Sjeremylt       if (priorities) *priorities[i] = backends[i].priority;
665d0c91ce9Sjeremylt       *n += 1;
666d0c91ce9Sjeremylt     }
667d0c91ce9Sjeremylt   }
668*6574a04fSJeremy L Thompson   CeedCheck(*n, NULL, CEED_ERROR_MAJOR, "No backends installed");
669d0c91ce9Sjeremylt   *resources = realloc(*resources, *n * sizeof(**resources));
670*6574a04fSJeremy L Thompson   CeedCheck(resources, NULL, CEED_ERROR_MAJOR, "realloc() failure");
671d0c91ce9Sjeremylt   if (priorities) {
672d0c91ce9Sjeremylt     *priorities = realloc(*priorities, *n * sizeof(**priorities));
673*6574a04fSJeremy L Thompson     CeedCheck(priorities, NULL, CEED_ERROR_MAJOR, "realloc() failure");
67422e44211Sjeremylt   }
67522e44211Sjeremylt   return CEED_ERROR_SUCCESS;
67645f1e315Sjeremylt }
67722e44211Sjeremylt // LCOV_EXCL_STOP
67822e44211Sjeremylt 
67922e44211Sjeremylt /**
680d79b80ecSjeremylt   @brief Initialize a \ref Ceed context to use the specified resource.
681ea61e9acSJeremy 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
682ea61e9acSJeremy L Thompson list of current available backend resources to stderr.
683b11c1e72Sjeremylt 
684ea61e9acSJeremy L Thompson   @param[in]  resource Resource to use, e.g., "/cpu/self"
685ea61e9acSJeremy L Thompson   @param[out] ceed     The library context
686b11c1e72Sjeremylt   @sa CeedRegister() CeedDestroy()
687b11c1e72Sjeremylt 
688b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
689dfdf5a53Sjeremylt 
6907a982d89SJeremy L. Thompson   @ref User
691b11c1e72Sjeremylt **/
692d7b241e6Sjeremylt int CeedInit(const char *resource, Ceed *ceed) {
6932b730f8bSJeremy L Thompson   size_t match_len = 0, match_index = UINT_MAX, match_priority = CEED_MAX_BACKEND_PRIORITY, priority;
694d7b241e6Sjeremylt 
695fe2413ffSjeremylt   // Find matching backend
696*6574a04fSJeremy L Thompson   CeedCheck(resource, NULL, CEED_ERROR_MAJOR, "No resource provided");
6972b730f8bSJeremy L Thompson   CeedCall(CeedRegisterAll());
69813873f79Sjeremylt 
69922e44211Sjeremylt   // Check for help request
70022e44211Sjeremylt   const char *help_prefix = "help";
7012b730f8bSJeremy L Thompson   size_t      match_help  = 0;
7022b730f8bSJeremy L Thompson   while (match_help < 4 && resource[match_help] == help_prefix[match_help]) match_help++;
70322e44211Sjeremylt   if (match_help == 4) {
7042b730f8bSJeremy L Thompson     fprintf(stderr, "libCEED version: %d.%d%d%s\n", CEED_VERSION_MAJOR, CEED_VERSION_MINOR, CEED_VERSION_PATCH,
70522e44211Sjeremylt             CEED_VERSION_RELEASE ? "" : "+development");
70692ee7d1cSjeremylt     fprintf(stderr, "Available backend resources:\n");
70722e44211Sjeremylt     for (size_t i = 0; i < num_backends; i++) {
708d0c91ce9Sjeremylt       // Only report compiled backends
7092b730f8bSJeremy L Thompson       if (backends[i].priority < CEED_MAX_BACKEND_PRIORITY) fprintf(stderr, "  %s\n", backends[i].prefix);
71022e44211Sjeremylt     }
71122e44211Sjeremylt     fflush(stderr);
71222e44211Sjeremylt     match_help = 5;  // Delineating character expected
71322e44211Sjeremylt   } else {
71422e44211Sjeremylt     match_help = 0;
71522e44211Sjeremylt   }
71622e44211Sjeremylt 
717ea61e9acSJeremy L Thompson   // Find best match, computed as number of matching characters from requested resource stem
7182b730f8bSJeremy L Thompson   size_t stem_length = 0;
7192b730f8bSJeremy L Thompson   while (resource[stem_length + match_help] && resource[stem_length + match_help] != ':') stem_length++;
720d7b241e6Sjeremylt   for (size_t i = 0; i < num_backends; i++) {
7212b730f8bSJeremy L Thompson     size_t      n      = 0;
722d7b241e6Sjeremylt     const char *prefix = backends[i].prefix;
7232b730f8bSJeremy L Thompson     while (prefix[n] && prefix[n] == resource[n + match_help]) n++;
724d7b241e6Sjeremylt     priority = backends[i].priority;
725d1d35e2fSjeremylt     if (n > match_len || (n == match_len && match_priority > priority)) {
726d1d35e2fSjeremylt       match_len      = n;
727d1d35e2fSjeremylt       match_priority = priority;
728f7e22acaSJeremy L Thompson       match_index    = i;
729d7b241e6Sjeremylt     }
730d7b241e6Sjeremylt   }
7319c9a0587SLeila Ghaffari   // Using Levenshtein distance to find closest match
7329c9a0587SLeila Ghaffari   if (match_len <= 1 || match_len != stem_length) {
733203015caSLeila Ghaffari     // LCOV_EXCL_START
7349c9a0587SLeila Ghaffari     size_t lev_dis   = UINT_MAX;
735f7e22acaSJeremy L Thompson     size_t lev_index = UINT_MAX, lev_priority = CEED_MAX_BACKEND_PRIORITY;
7369c9a0587SLeila Ghaffari     for (size_t i = 0; i < num_backends; i++) {
7379c9a0587SLeila Ghaffari       const char *prefix        = backends[i].prefix;
7389c9a0587SLeila Ghaffari       size_t      prefix_length = strlen(backends[i].prefix);
7399c9a0587SLeila Ghaffari       size_t      min_len       = (prefix_length < stem_length) ? prefix_length : stem_length;
740092904ddSLeila Ghaffari       size_t      column[min_len + 1];
741092904ddSLeila Ghaffari       for (size_t j = 0; j <= min_len; j++) column[j] = j;
7429c9a0587SLeila Ghaffari       for (size_t j = 1; j <= min_len; j++) {
7439c9a0587SLeila Ghaffari         column[0] = j;
7449c9a0587SLeila Ghaffari         for (size_t k = 1, last_diag = j - 1; k <= min_len; k++) {
745092904ddSLeila Ghaffari           size_t old_diag = column[k];
7469c9a0587SLeila Ghaffari           size_t min_1    = (column[k] < column[k - 1]) ? column[k] + 1 : column[k - 1] + 1;
7479c9a0587SLeila Ghaffari           size_t min_2    = last_diag + (resource[k - 1] == prefix[j - 1] ? 0 : 1);
7489c9a0587SLeila Ghaffari           column[k]       = (min_1 < min_2) ? min_1 : min_2;
7499c9a0587SLeila Ghaffari           last_diag       = old_diag;
7509c9a0587SLeila Ghaffari         }
7519c9a0587SLeila Ghaffari       }
7529c9a0587SLeila Ghaffari       size_t n = column[min_len];
7539c9a0587SLeila Ghaffari       priority = backends[i].priority;
7542b730f8bSJeremy L Thompson       if (n < lev_dis || (n == lev_dis && lev_priority > priority)) {
7559c9a0587SLeila Ghaffari         lev_dis      = n;
7569c9a0587SLeila Ghaffari         lev_priority = priority;
757f7e22acaSJeremy L Thompson         lev_index    = i;
7589c9a0587SLeila Ghaffari       }
7599c9a0587SLeila Ghaffari     }
760f7e22acaSJeremy L Thompson     const char *prefix_lev = backends[lev_index].prefix;
7612b730f8bSJeremy L Thompson     size_t      lev_length = 0;
7622b730f8bSJeremy L Thompson     while (prefix_lev[lev_length] && prefix_lev[lev_length] != '\0') lev_length++;
7639c9a0587SLeila Ghaffari     size_t m = (lev_length < stem_length) ? lev_length : stem_length;
764*6574a04fSJeremy L Thompson     if (lev_dis + 1 >= m) return CeedError(NULL, CEED_ERROR_MAJOR, "No suitable backend: %s", resource);
765*6574a04fSJeremy L Thompson     else return CeedError(NULL, CEED_ERROR_MAJOR, "No suitable backend: %s\nClosest match: %s", resource, backends[lev_index].prefix);
766203015caSLeila Ghaffari     // LCOV_EXCL_STOP
7679c9a0587SLeila Ghaffari   }
768fe2413ffSjeremylt 
769fe2413ffSjeremylt   // Setup Ceed
7702b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, ceed));
7712b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, &(*ceed)->jit_source_roots));
772bc81ce41Sjeremylt   const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER");
7732b730f8bSJeremy L Thompson   if (!ceed_error_handler) ceed_error_handler = "abort";
7742b730f8bSJeremy L Thompson   if (!strcmp(ceed_error_handler, "exit")) (*ceed)->Error = CeedErrorExit;
7752b730f8bSJeremy L Thompson   else if (!strcmp(ceed_error_handler, "store")) (*ceed)->Error = CeedErrorStore;
7762b730f8bSJeremy L Thompson   else (*ceed)->Error = CeedErrorAbort;
777d1d35e2fSjeremylt   memcpy((*ceed)->err_msg, "No error message stored", 24);
778d1d35e2fSjeremylt   (*ceed)->ref_count = 1;
779d7b241e6Sjeremylt   (*ceed)->data      = NULL;
780fe2413ffSjeremylt 
781fe2413ffSjeremylt   // Set lookup table
782d1d35e2fSjeremylt   FOffset f_offsets[] = {
7836e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, Error),
7846e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, GetPreferredMemType),
7856e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, Destroy),
786f8902d9eSjeremylt       CEED_FTABLE_ENTRY(Ceed, VectorCreate),
7876e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreate),
788fc0567d9Srezgarshakeri       CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateOriented),
7896e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked),
7906e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1),
7916e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, BasisCreateH1),
79250c301a5SRezgar Shakeri       CEED_FTABLE_ENTRY(Ceed, BasisCreateHdiv),
793c4e3f59bSSebastian Grimberg       CEED_FTABLE_ENTRY(Ceed, BasisCreateHcurl),
7946e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, TensorContractCreate),
7956e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, QFunctionCreate),
796777ff853SJeremy L Thompson       CEED_FTABLE_ENTRY(Ceed, QFunctionContextCreate),
7976e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, OperatorCreate),
7986e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate),
7999c774eddSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, HasValidArray),
8009c774eddSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, HasBorrowedArrayOfType),
8016e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, SetArray),
8026a6c615bSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, TakeArray),
8036e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, SetValue),
804f48ed27dSnbeams       CEED_FTABLE_ENTRY(CeedVector, SyncArray),
8056e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, GetArray),
8066e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, GetArrayRead),
8079c774eddSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, GetArrayWrite),
8086e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, RestoreArray),
8096e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead),
810547d9b97Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, Norm),
811e0dd3b27Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, Scale),
8120f7fd0f8Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, AXPY),
8135fb68f37SKaren (Ren) Stengel       CEED_FTABLE_ENTRY(CeedVector, AXPBY),
8140f7fd0f8Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, PointwiseMult),
815d99fa3c5SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, Reciprocal),
8166e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, Destroy),
8176e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedElemRestriction, Apply),
8186e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock),
819bd33150aSjeremylt       CEED_FTABLE_ENTRY(CeedElemRestriction, GetOffsets),
8206e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy),
8216e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedBasis, Apply),
8226e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedBasis, Destroy),
8236e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedTensorContract, Apply),
8246e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedTensorContract, Destroy),
8256e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedQFunction, Apply),
8268c84ac63Sjeremylt       CEED_FTABLE_ENTRY(CeedQFunction, SetCUDAUserFunction),
8278c84ac63Sjeremylt       CEED_FTABLE_ENTRY(CeedQFunction, SetHIPUserFunction),
8286e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedQFunction, Destroy),
8299c774eddSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, HasValidData),
8309c774eddSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, HasBorrowedDataOfType),
831777ff853SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, SetData),
832891038deSjeremylt       CEED_FTABLE_ENTRY(CeedQFunctionContext, TakeData),
833777ff853SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, GetData),
83428bfd0b7SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, GetDataRead),
835777ff853SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, RestoreData),
83628bfd0b7SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, RestoreDataRead),
8372e64a2b9SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, DataDestroy),
838777ff853SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, Destroy),
83980ac2e43SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunction),
84070a7ffb3SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunctionUpdate),
84180ac2e43SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleDiagonal),
8429e9210b8SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddDiagonal),
84380ac2e43SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssemblePointBlockDiagonal),
8449e9210b8SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddPointBlockDiagonal),
845e2f04181SAndrew T. Barker       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleSymbolic),
846e2f04181SAndrew T. Barker       CEED_FTABLE_ENTRY(CeedOperator, LinearAssemble),
847cefa2673SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleSingle),
848713f43c3Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, CreateFDMElementInverse),
8496e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, Apply),
850250756a7Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, ApplyComposite),
851cae8b89aSjeremylt       CEED_FTABLE_ENTRY(CeedOperator, ApplyAdd),
852250756a7Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, ApplyAddComposite),
8536e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian),
8546e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, Destroy),
8556e79d475Sjeremylt       {NULL, 0}  // End of lookup table - used in SetBackendFunction loop
8561dfeef1dSjeremylt   };
857fe2413ffSjeremylt 
8582b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(sizeof(f_offsets), &(*ceed)->f_offsets));
859d1d35e2fSjeremylt   memcpy((*ceed)->f_offsets, f_offsets, sizeof(f_offsets));
860fe2413ffSjeremylt 
8615107b09fSJeremy L Thompson   // Set fallback for advanced CeedOperator functions
862e2f04181SAndrew T. Barker   const char fallbackresource[] = "";
8632b730f8bSJeremy L Thompson   CeedCall(CeedSetOperatorFallbackResource(*ceed, fallbackresource));
8645107b09fSJeremy L Thompson 
86560f9e2d6SJeremy L Thompson   // Record env variables CEED_DEBUG or DBG
8662b730f8bSJeremy L Thompson   (*ceed)->is_debug = !!getenv("CEED_DEBUG") || !!getenv("DEBUG") || !!getenv("DBG");
86760f9e2d6SJeremy L Thompson 
86822e44211Sjeremylt   // Copy resource prefix, if backend setup successful
8692b730f8bSJeremy L Thompson   CeedCall(CeedStringAllocCopy(backends[match_index].prefix, (char **)&(*ceed)->resource));
870ee5a26f2SJeremy L Thompson 
871ee5a26f2SJeremy L Thompson   // Set default JiT source root
872ea61e9acSJeremy L Thompson   // Note: there will always be the default root for every Ceed but all additional paths are added to the top-most parent
8732b730f8bSJeremy L Thompson   CeedCall(CeedAddJitSourceRoot(*ceed, (char *)CeedJitSourceRootDefault));
874ee5a26f2SJeremy L Thompson 
875d04bbc78SJeremy L Thompson   // Backend specific setup
8762b730f8bSJeremy L Thompson   CeedCall(backends[match_index].init(&resource[match_help], *ceed));
877d04bbc78SJeremy L Thompson 
878e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
879d7b241e6Sjeremylt }
880d7b241e6Sjeremylt 
881d7b241e6Sjeremylt /**
882ea61e9acSJeremy L Thompson   @brief Copy the pointer to a Ceed context.
883512bb800SJeremy L Thompson            Both pointers should be destroyed with `CeedDestroy()`.
884512bb800SJeremy L Thompson 
885512bb800SJeremy 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.
886512bb800SJeremy L Thompson              This Ceed context will be destroyed if `ceed_copy` is the only reference to this Ceed context.
8879560d06aSjeremylt 
888ea61e9acSJeremy L Thompson   @param[in]     ceed      Ceed context to copy reference to
889ea61e9acSJeremy L Thompson   @param[in,out] ceed_copy Variable to store copied reference
8909560d06aSjeremylt 
8919560d06aSjeremylt   @return An error code: 0 - success, otherwise - failure
8929560d06aSjeremylt 
8939560d06aSjeremylt   @ref User
8949560d06aSjeremylt **/
8959560d06aSjeremylt int CeedReferenceCopy(Ceed ceed, Ceed *ceed_copy) {
8962b730f8bSJeremy L Thompson   CeedCall(CeedReference(ceed));
8972b730f8bSJeremy L Thompson   CeedCall(CeedDestroy(ceed_copy));
8989560d06aSjeremylt   *ceed_copy = ceed;
8999560d06aSjeremylt   return CEED_ERROR_SUCCESS;
9009560d06aSjeremylt }
9019560d06aSjeremylt 
9029560d06aSjeremylt /**
9037a982d89SJeremy L. Thompson   @brief Get the full resource name for a Ceed context
9042f86a920SJeremy L Thompson 
905ea61e9acSJeremy L Thompson   @param[in]  ceed     Ceed context to get resource name of
9067a982d89SJeremy L. Thompson   @param[out] resource Variable to store resource name
9072f86a920SJeremy L Thompson 
9082f86a920SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
9092f86a920SJeremy L Thompson 
9107a982d89SJeremy L. Thompson   @ref User
9115107b09fSJeremy L Thompson **/
9127a982d89SJeremy L. Thompson int CeedGetResource(Ceed ceed, const char **resource) {
9137a982d89SJeremy L. Thompson   *resource = (const char *)ceed->resource;
914e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
9155107b09fSJeremy L Thompson }
9165107b09fSJeremy L Thompson 
9175107b09fSJeremy L Thompson /**
918d79b80ecSjeremylt   @brief Return Ceed context preferred memory type
919c907536fSjeremylt 
920ea61e9acSJeremy L Thompson   @param[in]  ceed     Ceed context to get preferred memory type of
921d1d35e2fSjeremylt   @param[out] mem_type Address to save preferred memory type to
922c907536fSjeremylt 
923c907536fSjeremylt   @return An error code: 0 - success, otherwise - failure
924c907536fSjeremylt 
9257a982d89SJeremy L. Thompson   @ref User
926c907536fSjeremylt **/
927d1d35e2fSjeremylt int CeedGetPreferredMemType(Ceed ceed, CeedMemType *mem_type) {
928c907536fSjeremylt   if (ceed->GetPreferredMemType) {
9292b730f8bSJeremy L Thompson     CeedCall(ceed->GetPreferredMemType(mem_type));
930c907536fSjeremylt   } else {
931c263cd57Sjeremylt     Ceed delegate;
9322b730f8bSJeremy L Thompson     CeedCall(CeedGetDelegate(ceed, &delegate));
933c263cd57Sjeremylt 
934c263cd57Sjeremylt     if (delegate) {
9352b730f8bSJeremy L Thompson       CeedCall(CeedGetPreferredMemType(delegate, mem_type));
936c263cd57Sjeremylt     } else {
937d1d35e2fSjeremylt       *mem_type = CEED_MEM_HOST;
938c907536fSjeremylt     }
939c263cd57Sjeremylt   }
940e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
941c907536fSjeremylt }
942c907536fSjeremylt 
943c907536fSjeremylt /**
9449525855cSJeremy L Thompson   @brief Get deterministic status of Ceed
9459525855cSJeremy L Thompson 
9469525855cSJeremy L Thompson   @param[in]  ceed             Ceed
947d1d35e2fSjeremylt   @param[out] is_deterministic Variable to store deterministic status
9489525855cSJeremy L Thompson 
9499525855cSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
9509525855cSJeremy L Thompson 
9519525855cSJeremy L Thompson   @ref User
9529525855cSJeremy L Thompson **/
953d1d35e2fSjeremylt int CeedIsDeterministic(Ceed ceed, bool *is_deterministic) {
954d1d35e2fSjeremylt   *is_deterministic = ceed->is_deterministic;
955e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
9569525855cSJeremy L Thompson }
9579525855cSJeremy L Thompson 
9589525855cSJeremy L Thompson /**
959ee5a26f2SJeremy L Thompson   @brief Set additional JiT source root for Ceed
960ee5a26f2SJeremy L Thompson 
961ea61e9acSJeremy L Thompson   @param[in,out] ceed            Ceed
962ee5a26f2SJeremy L Thompson   @param[in]     jit_source_root Absolute path to additional JiT source directory
963ee5a26f2SJeremy L Thompson 
964ee5a26f2SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
965ee5a26f2SJeremy L Thompson 
966ee5a26f2SJeremy L Thompson   @ref User
967ee5a26f2SJeremy L Thompson **/
968ee5a26f2SJeremy L Thompson int CeedAddJitSourceRoot(Ceed ceed, const char *jit_source_root) {
9696155f12fSJeremy L Thompson   Ceed ceed_parent;
970ee5a26f2SJeremy L Thompson 
9712b730f8bSJeremy L Thompson   CeedCall(CeedGetParent(ceed, &ceed_parent));
9726155f12fSJeremy L Thompson 
9736155f12fSJeremy L Thompson   CeedInt index       = ceed_parent->num_jit_source_roots;
974ee5a26f2SJeremy L Thompson   size_t  path_length = strlen(jit_source_root);
9752b730f8bSJeremy L Thompson   CeedCall(CeedRealloc(index + 1, &ceed_parent->jit_source_roots));
9762b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(path_length + 1, &ceed_parent->jit_source_roots[index]));
977d602d780SJeremy L Thompson   memcpy(ceed_parent->jit_source_roots[index], jit_source_root, path_length);
9786155f12fSJeremy L Thompson   ceed_parent->num_jit_source_roots++;
979ee5a26f2SJeremy L Thompson 
980ee5a26f2SJeremy L Thompson   return CEED_ERROR_SUCCESS;
981ee5a26f2SJeremy L Thompson }
982ee5a26f2SJeremy L Thompson 
983ee5a26f2SJeremy L Thompson /**
9840a0da059Sjeremylt   @brief View a Ceed
9850a0da059Sjeremylt 
9860a0da059Sjeremylt   @param[in] ceed   Ceed to view
9870a0da059Sjeremylt   @param[in] stream Filestream to write to
9880a0da059Sjeremylt 
9890a0da059Sjeremylt   @return An error code: 0 - success, otherwise - failure
9900a0da059Sjeremylt 
9910a0da059Sjeremylt   @ref User
9920a0da059Sjeremylt **/
9930a0da059Sjeremylt int CeedView(Ceed ceed, FILE *stream) {
994d1d35e2fSjeremylt   CeedMemType mem_type;
9950a0da059Sjeremylt 
9962b730f8bSJeremy L Thompson   CeedCall(CeedGetPreferredMemType(ceed, &mem_type));
9970a0da059Sjeremylt 
9982b730f8bSJeremy L Thompson   fprintf(stream,
9992b730f8bSJeremy L Thompson           "Ceed\n"
10000a0da059Sjeremylt           "  Ceed Resource: %s\n"
10010a0da059Sjeremylt           "  Preferred MemType: %s\n",
1002d1d35e2fSjeremylt           ceed->resource, CeedMemTypes[mem_type]);
1003e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
10040a0da059Sjeremylt }
10050a0da059Sjeremylt 
10060a0da059Sjeremylt /**
1007b11c1e72Sjeremylt   @brief Destroy a Ceed context
1008d7b241e6Sjeremylt 
1009ea61e9acSJeremy L Thompson   @param[in,out] ceed Address of Ceed context to destroy
1010b11c1e72Sjeremylt 
1011b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1012dfdf5a53Sjeremylt 
10137a982d89SJeremy L. Thompson   @ref User
1014b11c1e72Sjeremylt **/
1015d7b241e6Sjeremylt int CeedDestroy(Ceed *ceed) {
1016ad6481ceSJeremy L Thompson   if (!*ceed || --(*ceed)->ref_count > 0) {
1017ad6481ceSJeremy L Thompson     *ceed = NULL;
1018ad6481ceSJeremy L Thompson     return CEED_ERROR_SUCCESS;
1019ad6481ceSJeremy L Thompson   }
10202b730f8bSJeremy L Thompson   if ((*ceed)->delegate) CeedCall(CeedDestroy(&(*ceed)->delegate));
10210ace9bf2Sjeremylt 
1022d1d35e2fSjeremylt   if ((*ceed)->obj_delegate_count > 0) {
102392ae7e47SJeremy L Thompson     for (CeedInt i = 0; i < (*ceed)->obj_delegate_count; i++) {
10242b730f8bSJeremy L Thompson       CeedCall(CeedDestroy(&((*ceed)->obj_delegates[i].delegate)));
10252b730f8bSJeremy L Thompson       CeedCall(CeedFree(&(*ceed)->obj_delegates[i].obj_name));
1026aefd8378Sjeremylt     }
10272b730f8bSJeremy L Thompson     CeedCall(CeedFree(&(*ceed)->obj_delegates));
1028aefd8378Sjeremylt   }
10290ace9bf2Sjeremylt 
10302b730f8bSJeremy L Thompson   if ((*ceed)->Destroy) CeedCall((*ceed)->Destroy(*ceed));
10310ace9bf2Sjeremylt 
103292ae7e47SJeremy L Thompson   for (CeedInt i = 0; i < (*ceed)->num_jit_source_roots; i++) {
10332b730f8bSJeremy L Thompson     CeedCall(CeedFree(&(*ceed)->jit_source_roots[i]));
1034032e71eaSJeremy L Thompson   }
10352b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*ceed)->jit_source_roots));
1036032e71eaSJeremy L Thompson 
10372b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*ceed)->f_offsets));
10382b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*ceed)->resource));
10392b730f8bSJeremy L Thompson   CeedCall(CeedDestroy(&(*ceed)->op_fallback_ceed));
10402b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*ceed)->op_fallback_resource));
10412b730f8bSJeremy L Thompson   CeedCall(CeedFree(ceed));
1042e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1043d7b241e6Sjeremylt }
1044d7b241e6Sjeremylt 
1045f9982c62SWill Pazner // LCOV_EXCL_START
1046f9982c62SWill Pazner const char *CeedErrorFormat(Ceed ceed, const char *format, va_list *args) {
10472b730f8bSJeremy L Thompson   if (ceed->parent) return CeedErrorFormat(ceed->parent, format, args);
10482b730f8bSJeremy L Thompson   if (ceed->op_fallback_parent) return CeedErrorFormat(ceed->op_fallback_parent, format, args);
104978464608Sjeremylt   // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized
105078464608Sjeremylt   vsnprintf(ceed->err_msg, CEED_MAX_RESOURCE_LEN, format, *args);  // NOLINT
1051d1d35e2fSjeremylt   return ceed->err_msg;
1052f9982c62SWill Pazner }
1053f9982c62SWill Pazner // LCOV_EXCL_STOP
1054f9982c62SWill Pazner 
10557a982d89SJeremy L. Thompson /**
10567a982d89SJeremy L. Thompson   @brief Error handling implementation; use \ref CeedError instead.
10577a982d89SJeremy L. Thompson 
10587a982d89SJeremy L. Thompson   @ref Developer
10597a982d89SJeremy L. Thompson **/
10602b730f8bSJeremy L Thompson int CeedErrorImpl(Ceed ceed, const char *filename, int lineno, const char *func, int ecode, const char *format, ...) {
10617a982d89SJeremy L. Thompson   va_list args;
1062d1d35e2fSjeremylt   int     ret_val;
10637a982d89SJeremy L. Thompson   va_start(args, format);
10647a982d89SJeremy L. Thompson   if (ceed) {
1065d1d35e2fSjeremylt     ret_val = ceed->Error(ceed, filename, lineno, func, ecode, format, &args);
10667a982d89SJeremy L. Thompson   } else {
1067b0d62198Sjeremylt     // LCOV_EXCL_START
1068477729cfSJeremy L Thompson     const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER");
10692b730f8bSJeremy L Thompson     if (!ceed_error_handler) ceed_error_handler = "abort";
10702b730f8bSJeremy L Thompson     if (!strcmp(ceed_error_handler, "return")) ret_val = CeedErrorReturn(ceed, filename, lineno, func, ecode, format, &args);
1071477729cfSJeremy L Thompson     else
1072477729cfSJeremy L Thompson       // This function will not return
1073d1d35e2fSjeremylt       ret_val = CeedErrorAbort(ceed, filename, lineno, func, ecode, format, &args);
10747a982d89SJeremy L. Thompson   }
10757a982d89SJeremy L. Thompson   va_end(args);
1076d1d35e2fSjeremylt   return ret_val;
1077b0d62198Sjeremylt   // LCOV_EXCL_STOP
10787a982d89SJeremy L. Thompson }
10797a982d89SJeremy L. Thompson 
1080477729cfSJeremy L Thompson /**
1081477729cfSJeremy L Thompson   @brief Error handler that returns without printing anything.
1082477729cfSJeremy L Thompson 
1083477729cfSJeremy L Thompson   Pass this to CeedSetErrorHandler() to obtain this error handling behavior.
1084477729cfSJeremy L Thompson 
1085477729cfSJeremy L Thompson   @ref Developer
1086477729cfSJeremy L Thompson **/
1087477729cfSJeremy L Thompson // LCOV_EXCL_START
10882b730f8bSJeremy L Thompson int CeedErrorReturn(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) {
1089d1d35e2fSjeremylt   return err_code;
1090477729cfSJeremy L Thompson }
1091477729cfSJeremy L Thompson // LCOV_EXCL_STOP
1092477729cfSJeremy L Thompson 
1093477729cfSJeremy L Thompson /**
1094ea61e9acSJeremy L Thompson   @brief Error handler that stores the error message for future use and returns the error.
1095477729cfSJeremy L Thompson 
1096477729cfSJeremy L Thompson   Pass this to CeedSetErrorHandler() to obtain this error handling behavior.
1097477729cfSJeremy L Thompson 
1098477729cfSJeremy L Thompson   @ref Developer
1099477729cfSJeremy L Thompson **/
1100477729cfSJeremy L Thompson // LCOV_EXCL_START
11012b730f8bSJeremy L Thompson int CeedErrorStore(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) {
11022b730f8bSJeremy L Thompson   if (ceed->parent) return CeedErrorStore(ceed->parent, filename, line_no, func, err_code, format, args);
11032b730f8bSJeremy L Thompson   if (ceed->op_fallback_parent) return CeedErrorStore(ceed->op_fallback_parent, filename, line_no, func, err_code, format, args);
1104477729cfSJeremy L Thompson 
1105477729cfSJeremy L Thompson   // Build message
1106990fdeb6SJeremy L Thompson   int len;
11072b730f8bSJeremy L Thompson   len = snprintf(ceed->err_msg, CEED_MAX_RESOURCE_LEN, "%s:%d in %s(): ", filename, line_no, func);
110878464608Sjeremylt   // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized
110978464608Sjeremylt   vsnprintf(ceed->err_msg + len, CEED_MAX_RESOURCE_LEN - len, format, *args);  // NOLINT
1110d1d35e2fSjeremylt   return err_code;
1111477729cfSJeremy L Thompson }
1112477729cfSJeremy L Thompson // LCOV_EXCL_STOP
1113477729cfSJeremy L Thompson 
1114477729cfSJeremy L Thompson /**
1115477729cfSJeremy L Thompson   @brief Error handler that prints to stderr and aborts
1116477729cfSJeremy L Thompson 
1117477729cfSJeremy L Thompson   Pass this to CeedSetErrorHandler() to obtain this error handling behavior.
1118477729cfSJeremy L Thompson 
1119477729cfSJeremy L Thompson   @ref Developer
1120477729cfSJeremy L Thompson **/
1121477729cfSJeremy L Thompson // LCOV_EXCL_START
11222b730f8bSJeremy L Thompson int CeedErrorAbort(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) {
1123d1d35e2fSjeremylt   fprintf(stderr, "%s:%d in %s(): ", filename, line_no, func);
1124f9982c62SWill Pazner   vfprintf(stderr, format, *args);
1125477729cfSJeremy L Thompson   fprintf(stderr, "\n");
1126477729cfSJeremy L Thompson   abort();
1127d1d35e2fSjeremylt   return err_code;
1128477729cfSJeremy L Thompson }
1129477729cfSJeremy L Thompson // LCOV_EXCL_STOP
1130477729cfSJeremy L Thompson 
1131477729cfSJeremy L Thompson /**
1132477729cfSJeremy L Thompson   @brief Error handler that prints to stderr and exits
1133477729cfSJeremy L Thompson 
1134477729cfSJeremy L Thompson   Pass this to CeedSetErrorHandler() to obtain this error handling behavior.
1135477729cfSJeremy L Thompson 
1136ea61e9acSJeremy L Thompson   In contrast to CeedErrorAbort(), this exits without a signal, so atexit() handlers (e.g., as used by gcov) are run.
1137477729cfSJeremy L Thompson 
1138477729cfSJeremy L Thompson   @ref Developer
1139477729cfSJeremy L Thompson **/
11402b730f8bSJeremy L Thompson int CeedErrorExit(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) {
1141d1d35e2fSjeremylt   fprintf(stderr, "%s:%d in %s(): ", filename, line_no, func);
114278464608Sjeremylt   // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized
114378464608Sjeremylt   vfprintf(stderr, format, *args);  // NOLINT
1144477729cfSJeremy L Thompson   fprintf(stderr, "\n");
1145d1d35e2fSjeremylt   exit(err_code);
1146d1d35e2fSjeremylt   return err_code;
1147477729cfSJeremy L Thompson }
1148477729cfSJeremy L Thompson 
1149477729cfSJeremy L Thompson /**
1150477729cfSJeremy L Thompson   @brief Set error handler
1151477729cfSJeremy L Thompson 
1152ea61e9acSJeremy L Thompson   A default error handler is set in CeedInit().
1153ea61e9acSJeremy L Thompson   Use this function to change the error handler to CeedErrorReturn(), CeedErrorAbort(), or a user-defined error handler.
1154477729cfSJeremy L Thompson 
1155477729cfSJeremy L Thompson   @ref Developer
1156477729cfSJeremy L Thompson **/
1157d1d35e2fSjeremylt int CeedSetErrorHandler(Ceed ceed, CeedErrorHandler handler) {
1158d1d35e2fSjeremylt   ceed->Error = handler;
1159d1d35e2fSjeremylt   if (ceed->delegate) CeedSetErrorHandler(ceed->delegate, handler);
11602b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < ceed->obj_delegate_count; i++) CeedSetErrorHandler(ceed->obj_delegates[i].delegate, handler);
1161e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1162477729cfSJeremy L Thompson }
1163477729cfSJeremy L Thompson 
1164477729cfSJeremy L Thompson /**
1165477729cfSJeremy L Thompson   @brief Get error message
1166477729cfSJeremy L Thompson 
1167ea61e9acSJeremy L Thompson   The error message is only stored when using the error handler CeedErrorStore()
1168477729cfSJeremy L Thompson 
1169ea61e9acSJeremy L Thompson   @param[in]  ceed    Ceed context to retrieve error message
1170d1d35e2fSjeremylt   @param[out] err_msg Char pointer to hold error message
1171477729cfSJeremy L Thompson 
1172477729cfSJeremy L Thompson   @ref Developer
1173477729cfSJeremy L Thompson **/
1174d1d35e2fSjeremylt int CeedGetErrorMessage(Ceed ceed, const char **err_msg) {
11752b730f8bSJeremy L Thompson   if (ceed->parent) return CeedGetErrorMessage(ceed->parent, err_msg);
11762b730f8bSJeremy L Thompson   if (ceed->op_fallback_parent) return CeedGetErrorMessage(ceed->op_fallback_parent, err_msg);
1177d1d35e2fSjeremylt   *err_msg = ceed->err_msg;
1178e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1179477729cfSJeremy L Thompson }
1180477729cfSJeremy L Thompson 
1181477729cfSJeremy L Thompson /**
1182477729cfSJeremy L Thompson   @brief Restore error message
1183477729cfSJeremy L Thompson 
1184ea61e9acSJeremy L Thompson   The error message is only stored when using the error handler CeedErrorStore()
1185477729cfSJeremy L Thompson 
1186ea61e9acSJeremy L Thompson   @param[in]  ceed    Ceed context to restore error message
1187d1d35e2fSjeremylt   @param[out] err_msg Char pointer that holds error message
1188477729cfSJeremy L Thompson 
1189477729cfSJeremy L Thompson   @ref Developer
1190477729cfSJeremy L Thompson **/
1191d1d35e2fSjeremylt int CeedResetErrorMessage(Ceed ceed, const char **err_msg) {
11922b730f8bSJeremy L Thompson   if (ceed->parent) return CeedResetErrorMessage(ceed->parent, err_msg);
11932b730f8bSJeremy L Thompson   if (ceed->op_fallback_parent) return CeedResetErrorMessage(ceed->op_fallback_parent, err_msg);
1194d1d35e2fSjeremylt   *err_msg = NULL;
1195d1d35e2fSjeremylt   memcpy(ceed->err_msg, "No error message stored", 24);
1196e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1197477729cfSJeremy L Thompson }
1198477729cfSJeremy L Thompson 
11991070991dSJed Brown /**
12001070991dSJed Brown   @brief Get libCEED library version info
12011070991dSJed Brown 
1202ea61e9acSJeremy L Thompson   libCEED version numbers have the form major.minor.patch.
1203ea61e9acSJeremy L Thompson   Non-release versions may contain unstable interfaces.
12041070991dSJed Brown 
12051070991dSJed Brown   @param[out] major   Major version of the library
12061070991dSJed Brown   @param[out] minor   Minor version of the library
12071070991dSJed Brown   @param[out] patch   Patch (subminor) version of the library
12081070991dSJed Brown   @param[out] release True for releases; false for development branches.
12091070991dSJed Brown 
12101070991dSJed Brown   The caller may pass NULL for any arguments that are not needed.
12111070991dSJed Brown 
12121070991dSJed Brown   @sa CEED_VERSION_GE()
12131070991dSJed Brown 
12141070991dSJed Brown   @ref Developer
12151070991dSJed Brown */
12161070991dSJed Brown int CeedGetVersion(int *major, int *minor, int *patch, bool *release) {
12171070991dSJed Brown   if (major) *major = CEED_VERSION_MAJOR;
12181070991dSJed Brown   if (minor) *minor = CEED_VERSION_MINOR;
12191070991dSJed Brown   if (patch) *patch = CEED_VERSION_PATCH;
12201070991dSJed Brown   if (release) *release = CEED_VERSION_RELEASE;
12211070991dSJed Brown   return 0;
12221070991dSJed Brown }
12231070991dSJed Brown 
122480a9ef05SNatalie Beams int CeedGetScalarType(CeedScalarType *scalar_type) {
122580a9ef05SNatalie Beams   *scalar_type = CEED_SCALAR_TYPE;
122680a9ef05SNatalie Beams   return 0;
122780a9ef05SNatalie Beams }
122880a9ef05SNatalie Beams 
1229d7b241e6Sjeremylt /// @}
1230