xref: /libCEED/interface/ceed.c (revision bf84744c45d908693f8d34d79c45258a8cb93a26)
15aed82e4SJeremy L Thompson // Copyright (c) 2017-2024, 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 
31eaae1aeaSJames Wright #define CEED_FTABLE_ENTRY(class, method) {#class #method, offsetof(struct class##_private, method)}
32d7b241e6Sjeremylt /// @endcond
33d7b241e6Sjeremylt 
34d7b241e6Sjeremylt /// @file
35d7b241e6Sjeremylt /// Implementation of core components of Ceed library
367a982d89SJeremy L. Thompson 
377a982d89SJeremy L. Thompson /// @addtogroup CeedUser
38d7b241e6Sjeremylt /// @{
39d7b241e6Sjeremylt 
40dfdf5a53Sjeremylt /**
41dfdf5a53Sjeremylt   @brief Request immediate completion
42dfdf5a53Sjeremylt 
43ca94c3ddSJeremy L Thompson   This predefined constant is passed as the @ref CeedRequest argument to interfaces when the caller wishes for the operation to be performed immediately.
44ca94c3ddSJeremy L Thompson   The code
45dfdf5a53Sjeremylt 
46dfdf5a53Sjeremylt   @code
47dfdf5a53Sjeremylt     CeedOperatorApply(op, ..., CEED_REQUEST_IMMEDIATE);
48dfdf5a53Sjeremylt   @endcode
49dfdf5a53Sjeremylt 
50dfdf5a53Sjeremylt   is semantically equivalent to
51dfdf5a53Sjeremylt 
52dfdf5a53Sjeremylt   @code
53dfdf5a53Sjeremylt     CeedRequest request;
54dfdf5a53Sjeremylt     CeedOperatorApply(op, ..., &request);
55dfdf5a53Sjeremylt     CeedRequestWait(&request);
56dfdf5a53Sjeremylt   @endcode
57dfdf5a53Sjeremylt 
58dfdf5a53Sjeremylt   @sa CEED_REQUEST_ORDERED
59dfdf5a53Sjeremylt **/
60d7b241e6Sjeremylt CeedRequest *const CEED_REQUEST_IMMEDIATE = &ceed_request_immediate;
61d7b241e6Sjeremylt 
62d7b241e6Sjeremylt /**
63b11c1e72Sjeremylt   @brief Request ordered completion
64d7b241e6Sjeremylt 
65ca94c3ddSJeremy 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 order that it is submitted to the device.
66ca94c3ddSJeremy L Thompson   It is typically used in a construct such as:
67d7b241e6Sjeremylt 
68d7b241e6Sjeremylt   @code
69d7b241e6Sjeremylt     CeedRequest request;
70d7b241e6Sjeremylt     CeedOperatorApply(op1, ..., CEED_REQUEST_ORDERED);
71d7b241e6Sjeremylt     CeedOperatorApply(op2, ..., &request);
72d7b241e6Sjeremylt     // other optional work
738b2d6f4aSMatthew Knepley     CeedRequestWait(&request);
74d7b241e6Sjeremylt   @endcode
75d7b241e6Sjeremylt 
76ea61e9acSJeremy L Thompson   which allows the sequence to complete asynchronously but does not start `op2` until `op1` has completed.
77d7b241e6Sjeremylt 
78ea61e9acSJeremy L Thompson   @todo The current implementation is overly strict, offering equivalent semantics to @ref CEED_REQUEST_IMMEDIATE.
79d7b241e6Sjeremylt 
80d7b241e6Sjeremylt   @sa CEED_REQUEST_IMMEDIATE
81d7b241e6Sjeremylt  */
82d7b241e6Sjeremylt CeedRequest *const CEED_REQUEST_ORDERED = &ceed_request_ordered;
83d7b241e6Sjeremylt 
84b11c1e72Sjeremylt /**
85ca94c3ddSJeremy L Thompson   @brief Wait for a @ref CeedRequest to complete.
86dfdf5a53Sjeremylt 
87ca94c3ddSJeremy L Thompson   Calling @ref CeedRequestWait() on a `NULL` request is a no-op.
887a982d89SJeremy L. Thompson 
89ca94c3ddSJeremy L Thompson   @param[in,out] req Address of @ref CeedRequest to wait for; zeroed on completion.
907a982d89SJeremy L. Thompson 
917a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
927a982d89SJeremy L. Thompson 
937a982d89SJeremy L. Thompson   @ref User
94b11c1e72Sjeremylt **/
957a982d89SJeremy L. Thompson int CeedRequestWait(CeedRequest *req) {
962b730f8bSJeremy L Thompson   if (!*req) return CEED_ERROR_SUCCESS;
972b730f8bSJeremy L Thompson   return CeedError(NULL, CEED_ERROR_UNSUPPORTED, "CeedRequestWait not implemented");
98683faae0SJed Brown }
997a982d89SJeremy L. Thompson 
1007a982d89SJeremy L. Thompson /// @}
1017a982d89SJeremy L. Thompson 
1027a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
1037a982d89SJeremy L. Thompson /// Ceed Library Internal Functions
1047a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
1057a982d89SJeremy L. Thompson /// @addtogroup CeedDeveloper
1067a982d89SJeremy L. Thompson /// @{
107d7b241e6Sjeremylt 
1086a406739SJeremy L Thompson /**
1096a406739SJeremy L Thompson   @brief Register a Ceed backend internally.
1104385fb7fSSebastian Grimberg 
111ca94c3ddSJeremy L Thompson   Note: Backends should call @ref CeedRegister() instead.
1126a406739SJeremy L Thompson 
113ea61e9acSJeremy L Thompson   @param[in] prefix   Prefix of resources for this backend to respond to.
114ea61e9acSJeremy L Thompson                         For example, the reference backend responds to "/cpu/self".
115ca94c3ddSJeremy L Thompson   @param[in] init     Initialization function called by @ref CeedInit() when the backend is selected to drive the requested resource
116ea61e9acSJeremy L Thompson   @param[in] priority Integer priority.
117ca94c3ddSJeremy L Thompson                         Lower values are preferred in case the resource requested by @ref CeedInit() has non-unique best prefix match.
1186a406739SJeremy L Thompson 
1196a406739SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1206a406739SJeremy L Thompson 
1216a406739SJeremy L Thompson   @ref Developer
1226a406739SJeremy L Thompson **/
1232b730f8bSJeremy L Thompson int CeedRegisterImpl(const char *prefix, int (*init)(const char *, Ceed), unsigned int priority) {
12458c07c4fSSebastian Grimberg   int ierr = 0;
1256a406739SJeremy L Thompson 
12658c07c4fSSebastian Grimberg   CeedPragmaCritical(CeedRegisterImpl) {
12758c07c4fSSebastian Grimberg     if (num_backends < sizeof(backends) / sizeof(backends[0])) {
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++;
13358c07c4fSSebastian Grimberg     } else {
13458c07c4fSSebastian Grimberg       ierr = 1;
13558c07c4fSSebastian Grimberg     }
13658c07c4fSSebastian Grimberg   }
13758c07c4fSSebastian Grimberg   CeedCheck(ierr == 0, NULL, CEED_ERROR_MAJOR, "Too many 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 /**
150ca94c3ddSJeremy L Thompson   @brief Return value of `CEED_DEBUG` environment variable
15160f9e2d6SJeremy L Thompson 
152ca94c3ddSJeremy L Thompson   @param[in] ceed `Ceed` context
15360f9e2d6SJeremy L Thompson 
154ca94c3ddSJeremy 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 /**
164ca94c3ddSJeremy L Thompson   @brief Return value of `CEED_DEBUG` environment variable
16560f9e2d6SJeremy L Thompson 
166ca94c3ddSJeremy 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
1721c66c397SJeremy 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 
178ca94c3ddSJeremy L Thompson   @param[in] color  Color to print
179ca94c3ddSJeremy L Thompson   @param[in] 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 /**
198ca94c3ddSJeremy L Thompson   @brief Allocate an array on the host; use @ref 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
205ca94c3ddSJeremy L Thompson   @param[out] p    Address of pointer to hold the result
206b11c1e72Sjeremylt 
207b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
208b11c1e72Sjeremylt 
2097a982d89SJeremy L. Thompson   @ref Backend
210ca94c3ddSJeremy L Thompson 
211ca94c3ddSJeremy L Thompson   @sa CeedFree()
212b11c1e72Sjeremylt **/
213d7b241e6Sjeremylt int CeedMallocArray(size_t n, size_t unit, void *p) {
214d7b241e6Sjeremylt   int ierr = posix_memalign((void **)p, CEED_ALIGN, n * unit);
2156574a04fSJeremy L Thompson   CeedCheck(ierr == 0, NULL, CEED_ERROR_MAJOR, "posix_memalign failed to allocate %zd members of size %zd\n", n, unit);
216e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
217d7b241e6Sjeremylt }
218d7b241e6Sjeremylt 
219b11c1e72Sjeremylt /**
220ca94c3ddSJeremy L Thompson   @brief Allocate a cleared (zeroed) array on the host; use @ref CeedCalloc().
221b11c1e72Sjeremylt 
222b11c1e72Sjeremylt   Memory usage can be tracked by the library.
223b11c1e72Sjeremylt 
224ea61e9acSJeremy L Thompson   @param[in]  n    Number of units to allocate
225ea61e9acSJeremy L Thompson   @param[in]  unit Size of each unit
226ca94c3ddSJeremy L Thompson   @param[out] p    Address of pointer to hold the result
227b11c1e72Sjeremylt 
228b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
229b11c1e72Sjeremylt 
2307a982d89SJeremy L. Thompson   @ref Backend
231ca94c3ddSJeremy L Thompson 
232ca94c3ddSJeremy L Thompson   @sa CeedFree()
233b11c1e72Sjeremylt **/
234d7b241e6Sjeremylt int CeedCallocArray(size_t n, size_t unit, void *p) {
235d7b241e6Sjeremylt   *(void **)p = calloc(n, unit);
2366574a04fSJeremy L Thompson   CeedCheck(!n || !unit || *(void **)p, NULL, CEED_ERROR_MAJOR, "calloc failed to allocate %zd members of size %zd\n", n, unit);
237e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
238d7b241e6Sjeremylt }
239d7b241e6Sjeremylt 
240b11c1e72Sjeremylt /**
241ca94c3ddSJeremy L Thompson   @brief Reallocate an array on the host; use @ref CeedRealloc().
242b11c1e72Sjeremylt 
243b11c1e72Sjeremylt   Memory usage can be tracked by the library.
244b11c1e72Sjeremylt 
245ea61e9acSJeremy L Thompson   @param[in]  n    Number of units to allocate
246ea61e9acSJeremy L Thompson   @param[in]  unit Size of each unit
247ca94c3ddSJeremy L Thompson   @param[out] p    Address of pointer to hold the result
248b11c1e72Sjeremylt 
249b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
250b11c1e72Sjeremylt 
2517a982d89SJeremy L. Thompson   @ref Backend
252ca94c3ddSJeremy L Thompson 
253ca94c3ddSJeremy L Thompson   @sa CeedFree()
254b11c1e72Sjeremylt **/
255d7b241e6Sjeremylt int CeedReallocArray(size_t n, size_t unit, void *p) {
256d7b241e6Sjeremylt   *(void **)p = realloc(*(void **)p, n * unit);
2576574a04fSJeremy L Thompson   CeedCheck(!n || !unit || *(void **)p, NULL, CEED_ERROR_MAJOR, "realloc failed to allocate %zd members of size %zd\n", n, unit);
258e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
259d7b241e6Sjeremylt }
260d7b241e6Sjeremylt 
261f7e22acaSJeremy L Thompson /**
262ca94c3ddSJeremy L Thompson   @brief Allocate a cleared string buffer on the host.
263f7e22acaSJeremy L Thompson 
264f7e22acaSJeremy L Thompson   Memory usage can be tracked by the library.
265f7e22acaSJeremy L Thompson 
266ea61e9acSJeremy L Thompson   @param[in]  source Pointer to string to be copied
267ea61e9acSJeremy L Thompson   @param[out] copy   Pointer to variable to hold newly allocated string copy
268f7e22acaSJeremy L Thompson 
269f7e22acaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
270f7e22acaSJeremy L Thompson 
271f7e22acaSJeremy L Thompson   @ref Backend
272ca94c3ddSJeremy L Thompson 
273ca94c3ddSJeremy L Thompson   @sa CeedFree()
274f7e22acaSJeremy L Thompson **/
275f7e22acaSJeremy L Thompson int CeedStringAllocCopy(const char *source, char **copy) {
276f7e22acaSJeremy L Thompson   size_t len = strlen(source);
2772b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(len + 1, copy));
278d602d780SJeremy L Thompson   memcpy(*copy, source, len);
279f7e22acaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
280f7e22acaSJeremy L Thompson }
281f7e22acaSJeremy L Thompson 
282ca94c3ddSJeremy L Thompson /** Free memory allocated using @ref CeedMalloc() or @ref CeedCalloc()
28334138859Sjeremylt 
284ca94c3ddSJeremy L Thompson   @param[in,out] p Address of pointer to memory.
285ca94c3ddSJeremy 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 pointer.
286ca94c3ddSJeremy L Thompson 
287ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
288ca94c3ddSJeremy L Thompson 
289ca94c3ddSJeremy L Thompson   @ref Backend
29034138859Sjeremylt **/
291d7b241e6Sjeremylt int CeedFree(void *p) {
292d7b241e6Sjeremylt   free(*(void **)p);
293d7b241e6Sjeremylt   *(void **)p = NULL;
294e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
295d7b241e6Sjeremylt }
296d7b241e6Sjeremylt 
297f5d1e504SJeremy L Thompson /** Internal helper to manage handoff of user `source_array` to backend with proper @ref CeedCopyMode behavior.
298f5d1e504SJeremy L Thompson 
299f5d1e504SJeremy L Thompson   @param[in]     source_array          Source data provided by user
300f5d1e504SJeremy L Thompson   @param[in]     copy_mode             Copy mode for the data
301f5d1e504SJeremy L Thompson   @param[in]     num_values            Number of values to handle
30217afdf5cSJames Wright   @param[in]     size_unit             Size of array element in bytes
303f5d1e504SJeremy L Thompson   @param[in,out] target_array_owned    Pointer to location to allocated or hold owned data, may be freed if already allocated
304f5d1e504SJeremy L Thompson   @param[out]    target_array_borrowed Pointer to location to hold borrowed data
305f5d1e504SJeremy L Thompson   @param[out]    target_array          Pointer to location for data
306f5d1e504SJeremy L Thompson 
307f5d1e504SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
308f5d1e504SJeremy L Thompson 
309f5d1e504SJeremy L Thompson   @ref Backend
310f5d1e504SJeremy L Thompson **/
311f5d1e504SJeremy L Thompson static inline int CeedSetHostGenericArray(const void *source_array, CeedCopyMode copy_mode, size_t size_unit, CeedSize num_values,
312f5d1e504SJeremy L Thompson                                           void *target_array_owned, void *target_array_borrowed, void *target_array) {
313f5d1e504SJeremy L Thompson   switch (copy_mode) {
314f5d1e504SJeremy L Thompson     case CEED_COPY_VALUES:
315f5d1e504SJeremy L Thompson       if (!*(void **)target_array_owned) CeedCall(CeedCallocArray(num_values, size_unit, target_array_owned));
316f5d1e504SJeremy L Thompson       if (source_array) memcpy(*(void **)target_array_owned, source_array, size_unit * num_values);
317f5d1e504SJeremy L Thompson       *(void **)target_array_borrowed = NULL;
318f5d1e504SJeremy L Thompson       *(void **)target_array          = *(void **)target_array_owned;
319f5d1e504SJeremy L Thompson       break;
320f5d1e504SJeremy L Thompson     case CEED_OWN_POINTER:
321f5d1e504SJeremy L Thompson       CeedCall(CeedFree(target_array_owned));
322f5d1e504SJeremy L Thompson       *(void **)target_array_owned    = (void *)source_array;
323f5d1e504SJeremy L Thompson       *(void **)target_array_borrowed = NULL;
324f5d1e504SJeremy L Thompson       *(void **)target_array          = *(void **)target_array_owned;
325f5d1e504SJeremy L Thompson       break;
326f5d1e504SJeremy L Thompson     case CEED_USE_POINTER:
327f5d1e504SJeremy L Thompson       CeedCall(CeedFree(target_array_owned));
328f5d1e504SJeremy L Thompson       *(void **)target_array_owned    = NULL;
329f5d1e504SJeremy L Thompson       *(void **)target_array_borrowed = (void *)source_array;
330f5d1e504SJeremy L Thompson       *(void **)target_array          = *(void **)target_array_borrowed;
331f5d1e504SJeremy L Thompson   }
332f5d1e504SJeremy L Thompson   return CEED_ERROR_SUCCESS;
333f5d1e504SJeremy L Thompson }
334f5d1e504SJeremy L Thompson 
335f5d1e504SJeremy L Thompson /** Manage handoff of user `bool` `source_array` to backend with proper @ref CeedCopyMode behavior.
336f5d1e504SJeremy L Thompson 
337f5d1e504SJeremy L Thompson   @param[in]     source_array          Source data provided by user
338f5d1e504SJeremy L Thompson   @param[in]     copy_mode             Copy mode for the data
339f5d1e504SJeremy L Thompson   @param[in]     num_values            Number of values to handle
340f5d1e504SJeremy L Thompson   @param[in,out] target_array_owned    Pointer to location to allocated or hold owned data, may be freed if already allocated
341f5d1e504SJeremy L Thompson   @param[out]    target_array_borrowed Pointer to location to hold borrowed data
342f5d1e504SJeremy L Thompson   @param[out]    target_array          Pointer to location for data
343f5d1e504SJeremy L Thompson 
344f5d1e504SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
345f5d1e504SJeremy L Thompson 
346f5d1e504SJeremy L Thompson   @ref Backend
347f5d1e504SJeremy L Thompson **/
348f5d1e504SJeremy L Thompson int CeedSetHostBoolArray(const bool *source_array, CeedCopyMode copy_mode, CeedSize num_values, const bool **target_array_owned,
349f5d1e504SJeremy L Thompson                          const bool **target_array_borrowed, const bool **target_array) {
350f5d1e504SJeremy L Thompson   CeedCall(CeedSetHostGenericArray(source_array, copy_mode, sizeof(bool), num_values, target_array_owned, target_array_borrowed, target_array));
351f5d1e504SJeremy L Thompson   return CEED_ERROR_SUCCESS;
352f5d1e504SJeremy L Thompson }
353f5d1e504SJeremy L Thompson 
354f5d1e504SJeremy L Thompson /** Manage handoff of user `CeedInt8` `source_array` to backend with proper @ref CeedCopyMode behavior.
355f5d1e504SJeremy L Thompson 
356f5d1e504SJeremy L Thompson   @param[in]     source_array          Source data provided by user
357f5d1e504SJeremy L Thompson   @param[in]     copy_mode             Copy mode for the data
358f5d1e504SJeremy L Thompson   @param[in]     num_values            Number of values to handle
359f5d1e504SJeremy L Thompson   @param[in,out] target_array_owned    Pointer to location to allocated or hold owned data, may be freed if already allocated
360f5d1e504SJeremy L Thompson   @param[out]    target_array_borrowed Pointer to location to hold borrowed data
361f5d1e504SJeremy L Thompson   @param[out]    target_array          Pointer to location for data
362f5d1e504SJeremy L Thompson 
363f5d1e504SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
364f5d1e504SJeremy L Thompson 
365f5d1e504SJeremy L Thompson   @ref Backend
366f5d1e504SJeremy L Thompson **/
367f5d1e504SJeremy L Thompson int CeedSetHostCeedInt8Array(const CeedInt8 *source_array, CeedCopyMode copy_mode, CeedSize num_values, const CeedInt8 **target_array_owned,
368f5d1e504SJeremy L Thompson                              const CeedInt8 **target_array_borrowed, const CeedInt8 **target_array) {
369f5d1e504SJeremy L Thompson   CeedCall(CeedSetHostGenericArray(source_array, copy_mode, sizeof(CeedInt8), num_values, target_array_owned, target_array_borrowed, target_array));
370f5d1e504SJeremy L Thompson   return CEED_ERROR_SUCCESS;
371f5d1e504SJeremy L Thompson }
372f5d1e504SJeremy L Thompson 
373f5d1e504SJeremy L Thompson /** Manage handoff of user `CeedInt` `source_array` to backend with proper @ref CeedCopyMode behavior.
374f5d1e504SJeremy L Thompson 
375f5d1e504SJeremy L Thompson   @param[in]     source_array          Source data provided by user
376f5d1e504SJeremy L Thompson   @param[in]     copy_mode             Copy mode for the data
377f5d1e504SJeremy L Thompson   @param[in]     num_values            Number of values to handle
378f5d1e504SJeremy L Thompson   @param[in,out] target_array_owned    Pointer to location to allocated or hold owned data, may be freed if already allocated
379f5d1e504SJeremy L Thompson   @param[out]    target_array_borrowed Pointer to location to hold borrowed data
380f5d1e504SJeremy L Thompson   @param[out]    target_array          Pointer to location for data
381f5d1e504SJeremy L Thompson 
382f5d1e504SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
383f5d1e504SJeremy L Thompson 
384f5d1e504SJeremy L Thompson   @ref Backend
385f5d1e504SJeremy L Thompson **/
386f5d1e504SJeremy L Thompson int CeedSetHostCeedIntArray(const CeedInt *source_array, CeedCopyMode copy_mode, CeedSize num_values, const CeedInt **target_array_owned,
387f5d1e504SJeremy L Thompson                             const CeedInt **target_array_borrowed, const CeedInt **target_array) {
388f5d1e504SJeremy L Thompson   CeedCall(CeedSetHostGenericArray(source_array, copy_mode, sizeof(CeedInt), num_values, target_array_owned, target_array_borrowed, target_array));
389f5d1e504SJeremy L Thompson   return CEED_ERROR_SUCCESS;
390f5d1e504SJeremy L Thompson }
391f5d1e504SJeremy L Thompson 
392f5d1e504SJeremy L Thompson /** Manage handoff of user `CeedScalar` `source_array` to backend with proper @ref CeedCopyMode behavior.
393f5d1e504SJeremy L Thompson 
394f5d1e504SJeremy L Thompson   @param[in]     source_array          Source data provided by user
395f5d1e504SJeremy L Thompson   @param[in]     copy_mode             Copy mode for the data
396f5d1e504SJeremy L Thompson   @param[in]     num_values            Number of values to handle
397f5d1e504SJeremy L Thompson   @param[in,out] target_array_owned    Pointer to location to allocated or hold owned data, may be freed if already allocated
398f5d1e504SJeremy L Thompson   @param[out]    target_array_borrowed Pointer to location to hold borrowed data
399f5d1e504SJeremy L Thompson   @param[out]    target_array          Pointer to location for data
400f5d1e504SJeremy L Thompson 
401f5d1e504SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
402f5d1e504SJeremy L Thompson 
403f5d1e504SJeremy L Thompson   @ref Backend
404f5d1e504SJeremy L Thompson **/
405f5d1e504SJeremy L Thompson int CeedSetHostCeedScalarArray(const CeedScalar *source_array, CeedCopyMode copy_mode, CeedSize num_values, const CeedScalar **target_array_owned,
406f5d1e504SJeremy L Thompson                                const CeedScalar **target_array_borrowed, const CeedScalar **target_array) {
407f5d1e504SJeremy L Thompson   CeedCall(CeedSetHostGenericArray(source_array, copy_mode, sizeof(CeedScalar), num_values, target_array_owned, target_array_borrowed, target_array));
408f5d1e504SJeremy L Thompson   return CEED_ERROR_SUCCESS;
409f5d1e504SJeremy L Thompson }
410f5d1e504SJeremy L Thompson 
411d7b241e6Sjeremylt /**
412ca94c3ddSJeremy L Thompson   @brief Register a `Ceed` backend
413d7b241e6Sjeremylt 
414ea61e9acSJeremy L Thompson   @param[in] prefix   Prefix of resources for this backend to respond to.
415ea61e9acSJeremy L Thompson                         For example, the reference backend responds to "/cpu/self".
416ca94c3ddSJeremy L Thompson   @param[in] init     Initialization function called by @ref CeedInit() when the backend is selected to drive the requested resource
417ea61e9acSJeremy L Thompson   @param[in] priority Integer priority.
418ca94c3ddSJeremy L Thompson                         Lower values are preferred in case the resource requested by @ref CeedInit() has non-unique best prefix match.
419b11c1e72Sjeremylt 
420b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
421dfdf5a53Sjeremylt 
4227a982d89SJeremy L. Thompson   @ref Backend
423b11c1e72Sjeremylt **/
4242b730f8bSJeremy L Thompson int CeedRegister(const char *prefix, int (*init)(const char *, Ceed), unsigned int priority) {
42510243053SJeremy L Thompson   CeedDebugEnv("Backend Register: %s", prefix);
4266a406739SJeremy L Thompson   CeedRegisterImpl(prefix, init, priority);
427e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
428d7b241e6Sjeremylt }
429d7b241e6Sjeremylt 
430b11c1e72Sjeremylt /**
43160f9e2d6SJeremy L Thompson   @brief Return debugging status flag
43260f9e2d6SJeremy L Thompson 
433ca94c3ddSJeremy L Thompson   @param[in]  ceed     `Ceed` context to get debugging flag
434ea61e9acSJeremy L Thompson   @param[out] is_debug Variable to store debugging flag
43560f9e2d6SJeremy L Thompson 
43660f9e2d6SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
43760f9e2d6SJeremy L Thompson 
438d1d35e2fSjeremylt   @ref Backend
43960f9e2d6SJeremy L Thompson **/
440d1d35e2fSjeremylt int CeedIsDebug(Ceed ceed, bool *is_debug) {
4413f21f6b1SJeremy L Thompson   *is_debug = ceed->is_debug;
442e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
44360f9e2d6SJeremy L Thompson }
44460f9e2d6SJeremy L Thompson 
44560f9e2d6SJeremy L Thompson /**
446*bf84744cSJeremy L Thompson   @brief Get the root of the requested resource.
447*bf84744cSJeremy L Thompson 
448*bf84744cSJeremy L Thompson   Note: Caller is responsible for calling @ref CeedFree() on the `resource_root`.
449bc246734SJeremy L Thompson 
450ca94c3ddSJeremy L Thompson   @param[in]  ceed          `Ceed` context to get resource name of
451ca94c3ddSJeremy L Thompson   @param[in]  resource      Full user specified resource
452ca94c3ddSJeremy L Thompson   @param[in]  delineator    Delineator to break `resource_root` and `resource_spec`
453bc246734SJeremy L Thompson   @param[out] resource_root Variable to store resource root
454bc246734SJeremy L Thompson 
455bc246734SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
456bc246734SJeremy L Thompson 
457bc246734SJeremy L Thompson   @ref Backend
458bc246734SJeremy L Thompson **/
459bc246734SJeremy L Thompson int CeedGetResourceRoot(Ceed ceed, const char *resource, const char *delineator, char **resource_root) {
460bc246734SJeremy L Thompson   char  *device_spec       = strstr(resource, delineator);
461bc246734SJeremy L Thompson   size_t resource_root_len = device_spec ? (size_t)(device_spec - resource) + 1 : strlen(resource) + 1;
4621c66c397SJeremy L Thompson 
463bc246734SJeremy L Thompson   CeedCall(CeedCalloc(resource_root_len, resource_root));
464bc246734SJeremy L Thompson   memcpy(*resource_root, resource, resource_root_len - 1);
465bc246734SJeremy L Thompson   return CEED_ERROR_SUCCESS;
466bc246734SJeremy L Thompson }
467bc246734SJeremy L Thompson 
468bc246734SJeremy L Thompson /**
469ca94c3ddSJeremy L Thompson   @brief Retrieve a parent `Ceed` context
4707a982d89SJeremy L. Thompson 
471ca94c3ddSJeremy L Thompson   @param[in]  ceed   `Ceed` context to retrieve parent of
4727a982d89SJeremy L. Thompson   @param[out] parent Address to save the parent to
4737a982d89SJeremy L. Thompson 
4747a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4757a982d89SJeremy L. Thompson 
4767a982d89SJeremy L. Thompson   @ref Backend
4777a982d89SJeremy L. Thompson **/
4787a982d89SJeremy L. Thompson int CeedGetParent(Ceed ceed, Ceed *parent) {
4797a982d89SJeremy L. Thompson   if (ceed->parent) {
4802b730f8bSJeremy L Thompson     CeedCall(CeedGetParent(ceed->parent, parent));
481e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
4827a982d89SJeremy L. Thompson   }
4837a982d89SJeremy L. Thompson   *parent = ceed;
484e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4857a982d89SJeremy L. Thompson }
4867a982d89SJeremy L. Thompson 
4877a982d89SJeremy L. Thompson /**
488ca94c3ddSJeremy L Thompson   @brief Retrieve a delegate `Ceed` context
4897a982d89SJeremy L. Thompson 
490ca94c3ddSJeremy L Thompson   @param[in]  ceed     `Ceed` context to retrieve delegate of
4917a982d89SJeremy L. Thompson   @param[out] delegate Address to save the delegate to
4927a982d89SJeremy L. Thompson 
4937a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4947a982d89SJeremy L. Thompson 
4957a982d89SJeremy L. Thompson   @ref Backend
4967a982d89SJeremy L. Thompson **/
4977a982d89SJeremy L. Thompson int CeedGetDelegate(Ceed ceed, Ceed *delegate) {
4987a982d89SJeremy L. Thompson   *delegate = ceed->delegate;
499e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5007a982d89SJeremy L. Thompson }
5017a982d89SJeremy L. Thompson 
5027a982d89SJeremy L. Thompson /**
503ca94c3ddSJeremy L Thompson   @brief Set a delegate `Ceed` context
5047a982d89SJeremy L. Thompson 
505ca94c3ddSJeremy L Thompson   This function allows a `Ceed` context to set a delegate `Ceed` context.
506ca94c3ddSJeremy L Thompson   All backend implementations default to the delegate `Ceed` context, unless overridden.
5077a982d89SJeremy L. Thompson 
508ca94c3ddSJeremy L Thompson   @param[in]  ceed     `Ceed` context to set delegate of
5097a982d89SJeremy L. Thompson   @param[out] delegate Address to set the delegate to
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 CeedSetDelegate(Ceed ceed, Ceed delegate) {
5167a982d89SJeremy L. Thompson   ceed->delegate   = delegate;
5177a982d89SJeremy L. Thompson   delegate->parent = ceed;
518e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5197a982d89SJeremy L. Thompson }
5207a982d89SJeremy L. Thompson 
5217a982d89SJeremy L. Thompson /**
522ca94c3ddSJeremy L Thompson   @brief Retrieve a delegate `Ceed` context for a specific object type
5237a982d89SJeremy L. Thompson 
524ca94c3ddSJeremy L Thompson   @param[in]  ceed     `Ceed` context to retrieve delegate of
5257a982d89SJeremy L. Thompson   @param[out] delegate Address to save the delegate to
526d1d35e2fSjeremylt   @param[in]  obj_name Name of the object type to retrieve delegate for
5277a982d89SJeremy L. Thompson 
5287a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5297a982d89SJeremy L. Thompson 
5307a982d89SJeremy L. Thompson   @ref Backend
5317a982d89SJeremy L. Thompson **/
532d1d35e2fSjeremylt int CeedGetObjectDelegate(Ceed ceed, Ceed *delegate, const char *obj_name) {
5337a982d89SJeremy L. Thompson   // Check for object delegate
5342b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < ceed->obj_delegate_count; i++) {
535d1d35e2fSjeremylt     if (!strcmp(obj_name, ceed->obj_delegates->obj_name)) {
536d1d35e2fSjeremylt       *delegate = ceed->obj_delegates->delegate;
537e15f9bd0SJeremy L Thompson       return CEED_ERROR_SUCCESS;
5387a982d89SJeremy L. Thompson     }
5392b730f8bSJeremy L Thompson   }
5407a982d89SJeremy L. Thompson 
5417a982d89SJeremy L. Thompson   // Use default delegate if no object delegate
5422b730f8bSJeremy L Thompson   CeedCall(CeedGetDelegate(ceed, delegate));
543e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5447a982d89SJeremy L. Thompson }
5457a982d89SJeremy L. Thompson 
5467a982d89SJeremy L. Thompson /**
547ca94c3ddSJeremy L Thompson   @brief Set a delegate `Ceed` context for a specific object type
5487a982d89SJeremy L. Thompson 
549ca94c3ddSJeremy L Thompson   This function allows a `Ceed` context to set a delegate `Ceed` context for a given type of `Ceed` object.
550ca94c3ddSJeremy L Thompson   All backend implementations default to the delegate `Ceed` context for this object.
551ca94c3ddSJeremy L Thompson   For example, `CeedSetObjectDelegate(ceed, delegate, "Basis")` uses delegate implementations for all `CeedBasis` backend functions.
5527a982d89SJeremy L. Thompson 
553ca94c3ddSJeremy L Thompson   @param[in,out] ceed     `Ceed` context to set delegate of
554ca94c3ddSJeremy L Thompson   @param[in]     delegate `Ceed` context to use for delegation
555d1d35e2fSjeremylt   @param[in]     obj_name Name of the object type to set delegate for
5567a982d89SJeremy L. Thompson 
5577a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5587a982d89SJeremy L. Thompson 
5597a982d89SJeremy L. Thompson   @ref Backend
5607a982d89SJeremy L. Thompson **/
561d1d35e2fSjeremylt int CeedSetObjectDelegate(Ceed ceed, Ceed delegate, const char *obj_name) {
562d1d35e2fSjeremylt   CeedInt count = ceed->obj_delegate_count;
5637a982d89SJeremy L. Thompson 
5647a982d89SJeremy L. Thompson   // Malloc or Realloc
5657a982d89SJeremy L. Thompson   if (count) {
5662b730f8bSJeremy L Thompson     CeedCall(CeedRealloc(count + 1, &ceed->obj_delegates));
5677a982d89SJeremy L. Thompson   } else {
5682b730f8bSJeremy L Thompson     CeedCall(CeedCalloc(1, &ceed->obj_delegates));
5697a982d89SJeremy L. Thompson   }
570d1d35e2fSjeremylt   ceed->obj_delegate_count++;
5717a982d89SJeremy L. Thompson 
5727a982d89SJeremy L. Thompson   // Set object delegate
573d1d35e2fSjeremylt   ceed->obj_delegates[count].delegate = delegate;
5742b730f8bSJeremy L Thompson   CeedCall(CeedStringAllocCopy(obj_name, &ceed->obj_delegates[count].obj_name));
5757a982d89SJeremy L. Thompson 
5767a982d89SJeremy L. Thompson   // Set delegate parent
5777a982d89SJeremy L. Thompson   delegate->parent = ceed;
578e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5797a982d89SJeremy L. Thompson }
5807a982d89SJeremy L. Thompson 
5817a982d89SJeremy L. Thompson /**
582ca94c3ddSJeremy L Thompson   @brief Get the fallback resource for `CeedOperator`
5837a982d89SJeremy L. Thompson 
584ca94c3ddSJeremy L Thompson   @param[in]  ceed     `Ceed` context
5857a982d89SJeremy L. Thompson   @param[out] resource Variable to store fallback resource
5867a982d89SJeremy L. Thompson 
5877a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5887a982d89SJeremy L. Thompson 
5897a982d89SJeremy L. Thompson   @ref Backend
5907a982d89SJeremy L. Thompson **/
591363aefefSSebastian Grimberg int CeedGetOperatorFallbackResource(Ceed ceed, const char **resource) {
592d1d35e2fSjeremylt   *resource = (const char *)ceed->op_fallback_resource;
593e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5947a982d89SJeremy L. Thompson }
5957a982d89SJeremy L. Thompson 
5967a982d89SJeremy L. Thompson /**
597ca94c3ddSJeremy L Thompson   @brief Get the fallback `Ceed` for `CeedOperator`
5988687e1d4SJeremy L Thompson 
599ca94c3ddSJeremy L Thompson   @param[in]  ceed          `Ceed` context
600ca94c3ddSJeremy L Thompson   @param[out] fallback_ceed Variable to store fallback `Ceed`
6018687e1d4SJeremy L Thompson 
6028687e1d4SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
6038687e1d4SJeremy L Thompson 
6048687e1d4SJeremy L Thompson   @ref Backend
6058687e1d4SJeremy L Thompson **/
6068687e1d4SJeremy L Thompson int CeedGetOperatorFallbackCeed(Ceed ceed, Ceed *fallback_ceed) {
607d04bbc78SJeremy L Thompson   if (ceed->has_valid_op_fallback_resource) {
60823d4529eSJeremy L Thompson     CeedDebug256(ceed, CEED_DEBUG_COLOR_SUCCESS, "---------- CeedOperator Fallback ----------\n");
6092b730f8bSJeremy L Thompson     CeedDebug(ceed, "Getting fallback from %s to %s\n", ceed->resource, ceed->op_fallback_resource);
610d04bbc78SJeremy L Thompson   }
6118687e1d4SJeremy L Thompson 
612d04bbc78SJeremy L Thompson   // Create fallback Ceed if uninitalized
613d04bbc78SJeremy L Thompson   if (!ceed->op_fallback_ceed && ceed->has_valid_op_fallback_resource) {
61413f886e9SJeremy L Thompson     CeedDebug(ceed, "Creating fallback Ceed");
615d04bbc78SJeremy L Thompson 
6168687e1d4SJeremy L Thompson     Ceed        fallback_ceed;
617d04bbc78SJeremy L Thompson     const char *fallback_resource;
618d04bbc78SJeremy L Thompson 
619363aefefSSebastian Grimberg     CeedCall(CeedGetOperatorFallbackResource(ceed, &fallback_resource));
6202b730f8bSJeremy L Thompson     CeedCall(CeedInit(fallback_resource, &fallback_ceed));
6218687e1d4SJeremy L Thompson     fallback_ceed->op_fallback_parent = ceed;
6228687e1d4SJeremy L Thompson     fallback_ceed->Error              = ceed->Error;
6238687e1d4SJeremy L Thompson     ceed->op_fallback_ceed            = fallback_ceed;
6248687e1d4SJeremy L Thompson   }
6258687e1d4SJeremy L Thompson   *fallback_ceed = ceed->op_fallback_ceed;
6268687e1d4SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6278687e1d4SJeremy L Thompson }
6288687e1d4SJeremy L Thompson 
6298687e1d4SJeremy L Thompson /**
630ca94c3ddSJeremy L Thompson   @brief Set the fallback resource for `CeedOperator`.
6314385fb7fSSebastian Grimberg 
632ea61e9acSJeremy L Thompson   The current resource, if any, is freed by calling this function.
633ca94c3ddSJeremy L Thompson   This string is freed upon the destruction of the `Ceed` context.
6347a982d89SJeremy L. Thompson 
635ca94c3ddSJeremy L Thompson   @param[in,out] ceed     `Ceed` context
636ea61e9acSJeremy L Thompson   @param[in]     resource Fallback resource to set
6377a982d89SJeremy L. Thompson 
6387a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6397a982d89SJeremy L. Thompson 
6407a982d89SJeremy L. Thompson   @ref Backend
6417a982d89SJeremy L. Thompson **/
6427a982d89SJeremy L. Thompson int CeedSetOperatorFallbackResource(Ceed ceed, const char *resource) {
6437a982d89SJeremy L. Thompson   // Free old
6442b730f8bSJeremy L Thompson   CeedCall(CeedFree(&ceed->op_fallback_resource));
6457a982d89SJeremy L. Thompson 
6467a982d89SJeremy L. Thompson   // Set new
6472b730f8bSJeremy L Thompson   CeedCall(CeedStringAllocCopy(resource, (char **)&ceed->op_fallback_resource));
648d04bbc78SJeremy L Thompson 
649d04bbc78SJeremy L Thompson   // Check validity
6502b730f8bSJeremy L Thompson   ceed->has_valid_op_fallback_resource = ceed->op_fallback_resource && ceed->resource && strcmp(ceed->op_fallback_resource, ceed->resource);
651e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6527a982d89SJeremy L. Thompson }
6537a982d89SJeremy L. Thompson 
6547a982d89SJeremy L. Thompson /**
655ca94c3ddSJeremy L Thompson   @brief Flag `Ceed` context as deterministic
6569525855cSJeremy L Thompson 
657ca94c3ddSJeremy L Thompson   @param[in]  ceed             `Ceed` to flag as deterministic
65896b902e2Sjeremylt   @param[out] is_deterministic Deterministic status to set
6599525855cSJeremy L Thompson 
6609525855cSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
6619525855cSJeremy L Thompson 
6629525855cSJeremy L Thompson   @ref Backend
6639525855cSJeremy L Thompson **/
664d1d35e2fSjeremylt int CeedSetDeterministic(Ceed ceed, bool is_deterministic) {
665d1d35e2fSjeremylt   ceed->is_deterministic = is_deterministic;
666e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6679525855cSJeremy L Thompson }
6689525855cSJeremy L Thompson 
6699525855cSJeremy L Thompson /**
670ca94c3ddSJeremy L Thompson   @brief Set a backend function.
6717a982d89SJeremy L. Thompson 
672ea61e9acSJeremy L Thompson   This function is used for a backend to set the function associated with the Ceed objects.
673ca94c3ddSJeremy L Thompson   For example, `CeedSetBackendFunction(ceed, "Ceed", ceed, "VectorCreate", BackendVectorCreate)` sets the backend implementation of @ref CeedVectorCreate() and `CeedSetBackendFunction(ceed, "Basis", basis, "Apply", BackendBasisApply)` sets the backend implementation of @ref CeedBasisApply().
6749fd66db6SSebastian Grimberg   Note, the prefix 'Ceed' is not required for the object type ("Basis" vs "CeedBasis").
6757a982d89SJeremy L. Thompson 
676ca94c3ddSJeremy L Thompson   @param[in]  ceed      `Ceed` context for error handling
677ea61e9acSJeremy L Thompson   @param[in]  type      Type of Ceed object to set function for
6787a982d89SJeremy L. Thompson   @param[out] object    Ceed object to set function for
679ea61e9acSJeremy L Thompson   @param[in]  func_name Name of function to set
680ea61e9acSJeremy L Thompson   @param[in]  f         Function to set
6817a982d89SJeremy L. Thompson 
6827a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6837a982d89SJeremy L. Thompson 
6847a982d89SJeremy L. Thompson   @ref Backend
6857a982d89SJeremy L. Thompson **/
686897d4737SSebastian Grimberg int CeedSetBackendFunctionImpl(Ceed ceed, const char *type, void *object, const char *func_name, void (*f)(void)) {
687d1d35e2fSjeremylt   char lookup_name[CEED_MAX_RESOURCE_LEN + 1] = "";
6887a982d89SJeremy L. Thompson 
6897a982d89SJeremy L. Thompson   // Build lookup name
6902b730f8bSJeremy L Thompson   if (strcmp(type, "Ceed")) strncat(lookup_name, "Ceed", CEED_MAX_RESOURCE_LEN);
691d1d35e2fSjeremylt   strncat(lookup_name, type, CEED_MAX_RESOURCE_LEN);
692d1d35e2fSjeremylt   strncat(lookup_name, func_name, CEED_MAX_RESOURCE_LEN);
6937a982d89SJeremy L. Thompson 
6947a982d89SJeremy L. Thompson   // Find and use offset
6952b730f8bSJeremy L Thompson   for (CeedInt i = 0; ceed->f_offsets[i].func_name; i++) {
696d1d35e2fSjeremylt     if (!strcmp(ceed->f_offsets[i].func_name, lookup_name)) {
697d1d35e2fSjeremylt       size_t offset          = ceed->f_offsets[i].offset;
6987a982d89SJeremy L. Thompson       int (**fpointer)(void) = (int (**)(void))((char *)object + offset);  // *NOPAD*
6991c66c397SJeremy L Thompson 
700897d4737SSebastian Grimberg       *fpointer = (int (*)(void))f;
701e15f9bd0SJeremy L Thompson       return CEED_ERROR_SUCCESS;
7027a982d89SJeremy L. Thompson     }
7032b730f8bSJeremy L Thompson   }
7047a982d89SJeremy L. Thompson 
7057a982d89SJeremy L. Thompson   // LCOV_EXCL_START
7062b730f8bSJeremy L Thompson   return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Requested function '%s' was not found for CEED object '%s'", func_name, type);
7077a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
7087a982d89SJeremy L. Thompson }
7097a982d89SJeremy L. Thompson 
7107a982d89SJeremy L. Thompson /**
711ca94c3ddSJeremy L Thompson   @brief Retrieve backend data for a `Ceed` context
7127a982d89SJeremy L. Thompson 
713ca94c3ddSJeremy L Thompson   @param[in]  ceed `Ceed` context to retrieve data of
7147a982d89SJeremy L. Thompson   @param[out] data Address to save data to
7157a982d89SJeremy L. Thompson 
7167a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7177a982d89SJeremy L. Thompson 
7187a982d89SJeremy L. Thompson   @ref Backend
7197a982d89SJeremy L. Thompson **/
720777ff853SJeremy L Thompson int CeedGetData(Ceed ceed, void *data) {
721777ff853SJeremy L Thompson   *(void **)data = ceed->data;
722e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7237a982d89SJeremy L. Thompson }
7247a982d89SJeremy L. Thompson 
7257a982d89SJeremy L. Thompson /**
726ca94c3ddSJeremy L Thompson   @brief Set backend data for a `Ceed` context
7277a982d89SJeremy L. Thompson 
728ca94c3ddSJeremy L Thompson   @param[in,out] ceed `Ceed` context to set data of
729ea61e9acSJeremy L Thompson   @param[in]     data Address of data to set
7307a982d89SJeremy L. Thompson 
7317a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7327a982d89SJeremy L. Thompson 
7337a982d89SJeremy L. Thompson   @ref Backend
7347a982d89SJeremy L. Thompson **/
735777ff853SJeremy L Thompson int CeedSetData(Ceed ceed, void *data) {
736777ff853SJeremy L Thompson   ceed->data = data;
737e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7387a982d89SJeremy L. Thompson }
7397a982d89SJeremy L. Thompson 
74034359f16Sjeremylt /**
741ca94c3ddSJeremy L Thompson   @brief Increment the reference counter for a `Ceed` context
74234359f16Sjeremylt 
743ca94c3ddSJeremy L Thompson   @param[in,out] ceed `Ceed` context to increment the reference counter
74434359f16Sjeremylt 
74534359f16Sjeremylt   @return An error code: 0 - success, otherwise - failure
74634359f16Sjeremylt 
74734359f16Sjeremylt   @ref Backend
74834359f16Sjeremylt **/
7499560d06aSjeremylt int CeedReference(Ceed ceed) {
75034359f16Sjeremylt   ceed->ref_count++;
75134359f16Sjeremylt   return CEED_ERROR_SUCCESS;
75234359f16Sjeremylt }
75334359f16Sjeremylt 
7547a982d89SJeremy L. Thompson /// @}
7557a982d89SJeremy L. Thompson 
7567a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
7577a982d89SJeremy L. Thompson /// Ceed Public API
7587a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
7597a982d89SJeremy L. Thompson /// @addtogroup CeedUser
7607a982d89SJeremy L. Thompson /// @{
7617a982d89SJeremy L. Thompson 
7627a982d89SJeremy L. Thompson /**
763ca94c3ddSJeremy L Thompson   @brief Get the list of available resource names for `Ceed` contexts
7644385fb7fSSebastian Grimberg 
765ca94c3ddSJeremy L Thompson   Note: The caller is responsible for `free()`ing the resources and priorities arrays, but should not `free()` the contents of the resources array.
76622e44211Sjeremylt 
76792ee7d1cSjeremylt   @param[out] n          Number of available resources
76892ee7d1cSjeremylt   @param[out] resources  List of available resource names
76922e44211Sjeremylt   @param[out] priorities Resource name prioritization values, lower is better
77022e44211Sjeremylt 
77122e44211Sjeremylt   @return An error code: 0 - success, otherwise - failure
77222e44211Sjeremylt 
77322e44211Sjeremylt   @ref User
77422e44211Sjeremylt **/
77522e44211Sjeremylt // LCOV_EXCL_START
7762b730f8bSJeremy L Thompson int CeedRegistryGetList(size_t *n, char ***const resources, CeedInt **priorities) {
777d0c91ce9Sjeremylt   *n         = 0;
7789ff86846Sjeremylt   *resources = malloc(num_backends * sizeof(**resources));
7796574a04fSJeremy L Thompson   CeedCheck(resources, NULL, CEED_ERROR_MAJOR, "malloc() failure");
7809ff86846Sjeremylt   if (priorities) {
7819ff86846Sjeremylt     *priorities = malloc(num_backends * sizeof(**priorities));
7826574a04fSJeremy L Thompson     CeedCheck(priorities, NULL, CEED_ERROR_MAJOR, "malloc() failure");
7839ff86846Sjeremylt   }
78422e44211Sjeremylt   for (size_t i = 0; i < num_backends; i++) {
785d0c91ce9Sjeremylt     // Only report compiled backends
786d0c91ce9Sjeremylt     if (backends[i].priority < CEED_MAX_BACKEND_PRIORITY) {
78722e44211Sjeremylt       *resources[i] = backends[i].prefix;
7889ff86846Sjeremylt       if (priorities) *priorities[i] = backends[i].priority;
789d0c91ce9Sjeremylt       *n += 1;
790d0c91ce9Sjeremylt     }
791d0c91ce9Sjeremylt   }
7926574a04fSJeremy L Thompson   CeedCheck(*n, NULL, CEED_ERROR_MAJOR, "No backends installed");
793d0c91ce9Sjeremylt   *resources = realloc(*resources, *n * sizeof(**resources));
7946574a04fSJeremy L Thompson   CeedCheck(resources, NULL, CEED_ERROR_MAJOR, "realloc() failure");
795d0c91ce9Sjeremylt   if (priorities) {
796d0c91ce9Sjeremylt     *priorities = realloc(*priorities, *n * sizeof(**priorities));
7976574a04fSJeremy L Thompson     CeedCheck(priorities, NULL, CEED_ERROR_MAJOR, "realloc() failure");
79822e44211Sjeremylt   }
79922e44211Sjeremylt   return CEED_ERROR_SUCCESS;
80045f1e315Sjeremylt }
80122e44211Sjeremylt // LCOV_EXCL_STOP
80222e44211Sjeremylt 
80322e44211Sjeremylt /**
804ca94c3ddSJeremy L Thompson   @brief Initialize a `Ceed` context to use the specified resource.
8054385fb7fSSebastian Grimberg 
806ca94c3ddSJeremy L Thompson   Note: Prefixing the resource with "help:" (e.g. "help:/cpu/self") will result in @ref CeedInt() printing the current libCEED version number and a list of current available backend resources to `stderr`.
807b11c1e72Sjeremylt 
808ea61e9acSJeremy L Thompson   @param[in]  resource Resource to use, e.g., "/cpu/self"
809ea61e9acSJeremy L Thompson   @param[out] ceed     The library context
810b11c1e72Sjeremylt 
811b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
812dfdf5a53Sjeremylt 
8137a982d89SJeremy L. Thompson   @ref User
814ca94c3ddSJeremy L Thompson 
815ca94c3ddSJeremy L Thompson   @sa CeedRegister() CeedDestroy()
816b11c1e72Sjeremylt **/
817d7b241e6Sjeremylt int CeedInit(const char *resource, Ceed *ceed) {
8182b730f8bSJeremy L Thompson   size_t match_len = 0, match_index = UINT_MAX, match_priority = CEED_MAX_BACKEND_PRIORITY, priority;
819d7b241e6Sjeremylt 
820fe2413ffSjeremylt   // Find matching backend
8216574a04fSJeremy L Thompson   CeedCheck(resource, NULL, CEED_ERROR_MAJOR, "No resource provided");
8222b730f8bSJeremy L Thompson   CeedCall(CeedRegisterAll());
82313873f79Sjeremylt 
82422e44211Sjeremylt   // Check for help request
82522e44211Sjeremylt   const char *help_prefix = "help";
8262b730f8bSJeremy L Thompson   size_t      match_help  = 0;
8272b730f8bSJeremy L Thompson   while (match_help < 4 && resource[match_help] == help_prefix[match_help]) match_help++;
82822e44211Sjeremylt   if (match_help == 4) {
8292b730f8bSJeremy L Thompson     fprintf(stderr, "libCEED version: %d.%d%d%s\n", CEED_VERSION_MAJOR, CEED_VERSION_MINOR, CEED_VERSION_PATCH,
83022e44211Sjeremylt             CEED_VERSION_RELEASE ? "" : "+development");
83192ee7d1cSjeremylt     fprintf(stderr, "Available backend resources:\n");
83222e44211Sjeremylt     for (size_t i = 0; i < num_backends; i++) {
833d0c91ce9Sjeremylt       // Only report compiled backends
8342b730f8bSJeremy L Thompson       if (backends[i].priority < CEED_MAX_BACKEND_PRIORITY) fprintf(stderr, "  %s\n", backends[i].prefix);
83522e44211Sjeremylt     }
83622e44211Sjeremylt     fflush(stderr);
83722e44211Sjeremylt     match_help = 5;  // Delineating character expected
83822e44211Sjeremylt   } else {
83922e44211Sjeremylt     match_help = 0;
84022e44211Sjeremylt   }
84122e44211Sjeremylt 
842ea61e9acSJeremy L Thompson   // Find best match, computed as number of matching characters from requested resource stem
8432b730f8bSJeremy L Thompson   size_t stem_length = 0;
8442b730f8bSJeremy L Thompson   while (resource[stem_length + match_help] && resource[stem_length + match_help] != ':') stem_length++;
845d7b241e6Sjeremylt   for (size_t i = 0; i < num_backends; i++) {
8462b730f8bSJeremy L Thompson     size_t      n      = 0;
847d7b241e6Sjeremylt     const char *prefix = backends[i].prefix;
8482b730f8bSJeremy L Thompson     while (prefix[n] && prefix[n] == resource[n + match_help]) n++;
849d7b241e6Sjeremylt     priority = backends[i].priority;
850d1d35e2fSjeremylt     if (n > match_len || (n == match_len && match_priority > priority)) {
851d1d35e2fSjeremylt       match_len      = n;
852d1d35e2fSjeremylt       match_priority = priority;
853f7e22acaSJeremy L Thompson       match_index    = i;
854d7b241e6Sjeremylt     }
855d7b241e6Sjeremylt   }
8569c9a0587SLeila Ghaffari   // Using Levenshtein distance to find closest match
8579c9a0587SLeila Ghaffari   if (match_len <= 1 || match_len != stem_length) {
858203015caSLeila Ghaffari     // LCOV_EXCL_START
8599c9a0587SLeila Ghaffari     size_t lev_dis   = UINT_MAX;
860f7e22acaSJeremy L Thompson     size_t lev_index = UINT_MAX, lev_priority = CEED_MAX_BACKEND_PRIORITY;
8619c9a0587SLeila Ghaffari     for (size_t i = 0; i < num_backends; i++) {
8629c9a0587SLeila Ghaffari       const char *prefix        = backends[i].prefix;
8639c9a0587SLeila Ghaffari       size_t      prefix_length = strlen(backends[i].prefix);
8649c9a0587SLeila Ghaffari       size_t      min_len       = (prefix_length < stem_length) ? prefix_length : stem_length;
865092904ddSLeila Ghaffari       size_t      column[min_len + 1];
866092904ddSLeila Ghaffari       for (size_t j = 0; j <= min_len; j++) column[j] = j;
8679c9a0587SLeila Ghaffari       for (size_t j = 1; j <= min_len; j++) {
8689c9a0587SLeila Ghaffari         column[0] = j;
8699c9a0587SLeila Ghaffari         for (size_t k = 1, last_diag = j - 1; k <= min_len; k++) {
870092904ddSLeila Ghaffari           size_t old_diag = column[k];
8719c9a0587SLeila Ghaffari           size_t min_1    = (column[k] < column[k - 1]) ? column[k] + 1 : column[k - 1] + 1;
8729c9a0587SLeila Ghaffari           size_t min_2    = last_diag + (resource[k - 1] == prefix[j - 1] ? 0 : 1);
8739c9a0587SLeila Ghaffari           column[k]       = (min_1 < min_2) ? min_1 : min_2;
8749c9a0587SLeila Ghaffari           last_diag       = old_diag;
8759c9a0587SLeila Ghaffari         }
8769c9a0587SLeila Ghaffari       }
8779c9a0587SLeila Ghaffari       size_t n = column[min_len];
8789c9a0587SLeila Ghaffari       priority = backends[i].priority;
8792b730f8bSJeremy L Thompson       if (n < lev_dis || (n == lev_dis && lev_priority > priority)) {
8809c9a0587SLeila Ghaffari         lev_dis      = n;
8819c9a0587SLeila Ghaffari         lev_priority = priority;
882f7e22acaSJeremy L Thompson         lev_index    = i;
8839c9a0587SLeila Ghaffari       }
8849c9a0587SLeila Ghaffari     }
885f7e22acaSJeremy L Thompson     const char *prefix_lev = backends[lev_index].prefix;
8862b730f8bSJeremy L Thompson     size_t      lev_length = 0;
8872b730f8bSJeremy L Thompson     while (prefix_lev[lev_length] && prefix_lev[lev_length] != '\0') lev_length++;
8889c9a0587SLeila Ghaffari     size_t m = (lev_length < stem_length) ? lev_length : stem_length;
8896574a04fSJeremy L Thompson     if (lev_dis + 1 >= m) return CeedError(NULL, CEED_ERROR_MAJOR, "No suitable backend: %s", resource);
8906574a04fSJeremy L Thompson     else return CeedError(NULL, CEED_ERROR_MAJOR, "No suitable backend: %s\nClosest match: %s", resource, backends[lev_index].prefix);
891203015caSLeila Ghaffari     // LCOV_EXCL_STOP
8929c9a0587SLeila Ghaffari   }
893fe2413ffSjeremylt 
894fe2413ffSjeremylt   // Setup Ceed
8952b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, ceed));
8962b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, &(*ceed)->jit_source_roots));
897bc81ce41Sjeremylt   const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER");
8982b730f8bSJeremy L Thompson   if (!ceed_error_handler) ceed_error_handler = "abort";
8992b730f8bSJeremy L Thompson   if (!strcmp(ceed_error_handler, "exit")) (*ceed)->Error = CeedErrorExit;
9002b730f8bSJeremy L Thompson   else if (!strcmp(ceed_error_handler, "store")) (*ceed)->Error = CeedErrorStore;
9012b730f8bSJeremy L Thompson   else (*ceed)->Error = CeedErrorAbort;
902d1d35e2fSjeremylt   memcpy((*ceed)->err_msg, "No error message stored", 24);
903d1d35e2fSjeremylt   (*ceed)->ref_count = 1;
904d7b241e6Sjeremylt   (*ceed)->data      = NULL;
905fe2413ffSjeremylt 
906fe2413ffSjeremylt   // Set lookup table
907d1d35e2fSjeremylt   FOffset f_offsets[] = {
9086e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, Error),
9095ae360d4SJeremy L Thompson       CEED_FTABLE_ENTRY(Ceed, SetStream),
9106e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, GetPreferredMemType),
9116e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, Destroy),
912f8902d9eSjeremylt       CEED_FTABLE_ENTRY(Ceed, VectorCreate),
9136e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreate),
9143ac8f562SJeremy L Thompson       CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateAtPoints),
9156e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked),
9166e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1),
9176e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, BasisCreateH1),
91850c301a5SRezgar Shakeri       CEED_FTABLE_ENTRY(Ceed, BasisCreateHdiv),
919c4e3f59bSSebastian Grimberg       CEED_FTABLE_ENTRY(Ceed, BasisCreateHcurl),
9206e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, TensorContractCreate),
9216e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, QFunctionCreate),
922777ff853SJeremy L Thompson       CEED_FTABLE_ENTRY(Ceed, QFunctionContextCreate),
9236e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, OperatorCreate),
92448acf710SJeremy L Thompson       CEED_FTABLE_ENTRY(Ceed, OperatorCreateAtPoints),
9256e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate),
9269c774eddSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, HasValidArray),
9279c774eddSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, HasBorrowedArrayOfType),
9280b8f3c4eSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, CopyStrided),
9296e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, SetArray),
9306a6c615bSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, TakeArray),
9316e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, SetValue),
9320b8f3c4eSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, SetValueStrided),
933f48ed27dSnbeams       CEED_FTABLE_ENTRY(CeedVector, SyncArray),
9346e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, GetArray),
9356e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, GetArrayRead),
9369c774eddSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, GetArrayWrite),
9376e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, RestoreArray),
9386e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead),
939547d9b97Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, Norm),
940e0dd3b27Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, Scale),
9410f7fd0f8Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, AXPY),
9425fb68f37SKaren (Ren) Stengel       CEED_FTABLE_ENTRY(CeedVector, AXPBY),
9430f7fd0f8Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, PointwiseMult),
944d99fa3c5SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, Reciprocal),
9456e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, Destroy),
9466e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedElemRestriction, Apply),
947f30b1135SSebastian Grimberg       CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyUnsigned),
9487c1dbaffSSebastian Grimberg       CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyUnoriented),
94905fa913cSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyAtPointsInElement),
9506e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock),
951bd33150aSjeremylt       CEED_FTABLE_ENTRY(CeedElemRestriction, GetOffsets),
95277d1c127SSebastian Grimberg       CEED_FTABLE_ENTRY(CeedElemRestriction, GetOrientations),
95377d1c127SSebastian Grimberg       CEED_FTABLE_ENTRY(CeedElemRestriction, GetCurlOrientations),
95419605835SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedElemRestriction, GetAtPointsElementOffset),
9556e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy),
9566e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedBasis, Apply),
957db2becc9SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedBasis, ApplyAdd),
958c8c3fa7dSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedBasis, ApplyAtPoints),
959db2becc9SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedBasis, ApplyAddAtPoints),
9606e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedBasis, Destroy),
9616e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedTensorContract, Apply),
9626e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedTensorContract, Destroy),
9636e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedQFunction, Apply),
9648c84ac63Sjeremylt       CEED_FTABLE_ENTRY(CeedQFunction, SetCUDAUserFunction),
9658c84ac63Sjeremylt       CEED_FTABLE_ENTRY(CeedQFunction, SetHIPUserFunction),
9666e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedQFunction, Destroy),
9679c774eddSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, HasValidData),
9689c774eddSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, HasBorrowedDataOfType),
969777ff853SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, SetData),
970891038deSjeremylt       CEED_FTABLE_ENTRY(CeedQFunctionContext, TakeData),
971777ff853SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, GetData),
97228bfd0b7SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, GetDataRead),
973777ff853SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, RestoreData),
97428bfd0b7SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, RestoreDataRead),
9752e64a2b9SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, DataDestroy),
976777ff853SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, Destroy),
97780ac2e43SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunction),
97870a7ffb3SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunctionUpdate),
97980ac2e43SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleDiagonal),
9809e9210b8SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddDiagonal),
98180ac2e43SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssemblePointBlockDiagonal),
9829e9210b8SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddPointBlockDiagonal),
983e2f04181SAndrew T. Barker       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleSymbolic),
984e2f04181SAndrew T. Barker       CEED_FTABLE_ENTRY(CeedOperator, LinearAssemble),
985cefa2673SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleSingle),
986713f43c3Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, CreateFDMElementInverse),
9876e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, Apply),
988250756a7Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, ApplyComposite),
989cae8b89aSjeremylt       CEED_FTABLE_ENTRY(CeedOperator, ApplyAdd),
990250756a7Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, ApplyAddComposite),
9916e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian),
9926e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, Destroy),
9936e79d475Sjeremylt       {NULL, 0}  // End of lookup table - used in SetBackendFunction loop
9941dfeef1dSjeremylt   };
995fe2413ffSjeremylt 
9962b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(sizeof(f_offsets), &(*ceed)->f_offsets));
997d1d35e2fSjeremylt   memcpy((*ceed)->f_offsets, f_offsets, sizeof(f_offsets));
998fe2413ffSjeremylt 
9995107b09fSJeremy L Thompson   // Set fallback for advanced CeedOperator functions
1000ca735530SJeremy L Thompson   const char fallback_resource[] = "";
1001ca735530SJeremy L Thompson   CeedCall(CeedSetOperatorFallbackResource(*ceed, fallback_resource));
10025107b09fSJeremy L Thompson 
100360f9e2d6SJeremy L Thompson   // Record env variables CEED_DEBUG or DBG
10041c66c397SJeremy L Thompson   (*ceed)->is_debug = getenv("CEED_DEBUG") || getenv("DEBUG") || getenv("DBG");
100560f9e2d6SJeremy L Thompson 
100622e44211Sjeremylt   // Copy resource prefix, if backend setup successful
10072b730f8bSJeremy L Thompson   CeedCall(CeedStringAllocCopy(backends[match_index].prefix, (char **)&(*ceed)->resource));
1008ee5a26f2SJeremy L Thompson 
1009ee5a26f2SJeremy L Thompson   // Set default JiT source root
1010ea61e9acSJeremy L Thompson   // Note: there will always be the default root for every Ceed but all additional paths are added to the top-most parent
10112b730f8bSJeremy L Thompson   CeedCall(CeedAddJitSourceRoot(*ceed, (char *)CeedJitSourceRootDefault));
1012ee5a26f2SJeremy L Thompson 
1013d04bbc78SJeremy L Thompson   // Backend specific setup
10142b730f8bSJeremy L Thompson   CeedCall(backends[match_index].init(&resource[match_help], *ceed));
1015e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1016d7b241e6Sjeremylt }
1017d7b241e6Sjeremylt 
1018d7b241e6Sjeremylt /**
1019ca94c3ddSJeremy L Thompson   @brief Set the GPU stream for a `Ceed` context
10205ae360d4SJeremy L Thompson 
1021ca94c3ddSJeremy L Thompson   @param[in,out] ceed   `Ceed` context to set the stream
10225ae360d4SJeremy L Thompson   @param[in]     handle Handle to GPU stream
10235ae360d4SJeremy L Thompson 
10245ae360d4SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
10255ae360d4SJeremy L Thompson 
10265ae360d4SJeremy L Thompson   @ref User
10275ae360d4SJeremy L Thompson **/
10285ae360d4SJeremy L Thompson int CeedSetStream(Ceed ceed, void *handle) {
1029ca94c3ddSJeremy L Thompson   CeedCheck(handle, ceed, CEED_ERROR_INCOMPATIBLE, "Stream handle must be non-NULL");
10309ffb25e0SJames Wright   if (ceed->SetStream) {
10315ae360d4SJeremy L Thompson     CeedCall(ceed->SetStream(ceed, handle));
10329ffb25e0SJames Wright   } else {
10339ffb25e0SJames Wright     Ceed delegate;
10349ffb25e0SJames Wright     CeedCall(CeedGetDelegate(ceed, &delegate));
10355ae360d4SJeremy L Thompson 
103628ce3d2aSJeremy L Thompson     if (delegate) CeedCall(CeedSetStream(delegate, handle));
103728ce3d2aSJeremy L Thompson     else return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support setting stream");
10389ffb25e0SJames Wright   }
10395ae360d4SJeremy L Thompson   return CEED_ERROR_SUCCESS;
10405ae360d4SJeremy L Thompson }
10415ae360d4SJeremy L Thompson 
10425ae360d4SJeremy L Thompson /**
1043ca94c3ddSJeremy L Thompson   @brief Copy the pointer to a `Ceed` context.
10444385fb7fSSebastian Grimberg 
1045ca94c3ddSJeremy L Thompson   Both pointers should be destroyed with @ref CeedDestroy().
1046512bb800SJeremy L Thompson 
1047ca94c3ddSJeremy 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.
1048ca94c3ddSJeremy L Thompson         This `Ceed` context will be destroyed if `*ceed_copy` is the only reference to this `Ceed` context.
10499560d06aSjeremylt 
1050ca94c3ddSJeremy L Thompson   @param[in]     ceed      `Ceed` context to copy reference to
1051ea61e9acSJeremy L Thompson   @param[in,out] ceed_copy Variable to store copied reference
10529560d06aSjeremylt 
10539560d06aSjeremylt   @return An error code: 0 - success, otherwise - failure
10549560d06aSjeremylt 
10559560d06aSjeremylt   @ref User
10569560d06aSjeremylt **/
10579560d06aSjeremylt int CeedReferenceCopy(Ceed ceed, Ceed *ceed_copy) {
10582b730f8bSJeremy L Thompson   CeedCall(CeedReference(ceed));
10592b730f8bSJeremy L Thompson   CeedCall(CeedDestroy(ceed_copy));
10609560d06aSjeremylt   *ceed_copy = ceed;
10619560d06aSjeremylt   return CEED_ERROR_SUCCESS;
10629560d06aSjeremylt }
10639560d06aSjeremylt 
10649560d06aSjeremylt /**
1065ca94c3ddSJeremy L Thompson   @brief Get the full resource name for a `Ceed` context
10662f86a920SJeremy L Thompson 
1067ca94c3ddSJeremy L Thompson   @param[in]  ceed     `Ceed` context to get resource name of
10687a982d89SJeremy L. Thompson   @param[out] resource Variable to store resource name
10692f86a920SJeremy L Thompson 
10702f86a920SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
10712f86a920SJeremy L Thompson 
10727a982d89SJeremy L. Thompson   @ref User
10735107b09fSJeremy L Thompson **/
10747a982d89SJeremy L. Thompson int CeedGetResource(Ceed ceed, const char **resource) {
10757a982d89SJeremy L. Thompson   *resource = (const char *)ceed->resource;
1076e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
10775107b09fSJeremy L Thompson }
10785107b09fSJeremy L Thompson 
10795107b09fSJeremy L Thompson /**
1080ca94c3ddSJeremy L Thompson   @brief Return `Ceed` context preferred memory type
1081c907536fSjeremylt 
1082ca94c3ddSJeremy L Thompson   @param[in]  ceed     `Ceed` context to get preferred memory type of
1083d1d35e2fSjeremylt   @param[out] mem_type Address to save preferred memory type to
1084c907536fSjeremylt 
1085c907536fSjeremylt   @return An error code: 0 - success, otherwise - failure
1086c907536fSjeremylt 
10877a982d89SJeremy L. Thompson   @ref User
1088c907536fSjeremylt **/
1089d1d35e2fSjeremylt int CeedGetPreferredMemType(Ceed ceed, CeedMemType *mem_type) {
1090c907536fSjeremylt   if (ceed->GetPreferredMemType) {
10912b730f8bSJeremy L Thompson     CeedCall(ceed->GetPreferredMemType(mem_type));
1092c907536fSjeremylt   } else {
1093c263cd57Sjeremylt     Ceed delegate;
10942b730f8bSJeremy L Thompson     CeedCall(CeedGetDelegate(ceed, &delegate));
1095c263cd57Sjeremylt 
1096c263cd57Sjeremylt     if (delegate) {
10972b730f8bSJeremy L Thompson       CeedCall(CeedGetPreferredMemType(delegate, mem_type));
1098c263cd57Sjeremylt     } else {
1099d1d35e2fSjeremylt       *mem_type = CEED_MEM_HOST;
1100c907536fSjeremylt     }
1101c263cd57Sjeremylt   }
1102e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1103c907536fSjeremylt }
1104c907536fSjeremylt 
1105c907536fSjeremylt /**
1106ca94c3ddSJeremy L Thompson   @brief Get deterministic status of `Ceed` context
11079525855cSJeremy L Thompson 
1108ca94c3ddSJeremy L Thompson   @param[in]  ceed             `Ceed` context
1109d1d35e2fSjeremylt   @param[out] is_deterministic Variable to store deterministic status
11109525855cSJeremy L Thompson 
11119525855cSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
11129525855cSJeremy L Thompson 
11139525855cSJeremy L Thompson   @ref User
11149525855cSJeremy L Thompson **/
1115d1d35e2fSjeremylt int CeedIsDeterministic(Ceed ceed, bool *is_deterministic) {
1116d1d35e2fSjeremylt   *is_deterministic = ceed->is_deterministic;
1117e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
11189525855cSJeremy L Thompson }
11199525855cSJeremy L Thompson 
11209525855cSJeremy L Thompson /**
1121ca94c3ddSJeremy L Thompson   @brief Set additional JiT source root for `Ceed` context
1122ee5a26f2SJeremy L Thompson 
1123ca94c3ddSJeremy L Thompson   @param[in,out] ceed            `Ceed` context
1124ee5a26f2SJeremy L Thompson   @param[in]     jit_source_root Absolute path to additional JiT source directory
1125ee5a26f2SJeremy L Thompson 
1126ee5a26f2SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1127ee5a26f2SJeremy L Thompson 
1128ee5a26f2SJeremy L Thompson   @ref User
1129ee5a26f2SJeremy L Thompson **/
1130ee5a26f2SJeremy L Thompson int CeedAddJitSourceRoot(Ceed ceed, const char *jit_source_root) {
11316155f12fSJeremy L Thompson   Ceed ceed_parent;
1132ee5a26f2SJeremy L Thompson 
11332b730f8bSJeremy L Thompson   CeedCall(CeedGetParent(ceed, &ceed_parent));
11346155f12fSJeremy L Thompson 
11356155f12fSJeremy L Thompson   CeedInt index       = ceed_parent->num_jit_source_roots;
1136ee5a26f2SJeremy L Thompson   size_t  path_length = strlen(jit_source_root);
11371c66c397SJeremy L Thompson 
11382b730f8bSJeremy L Thompson   CeedCall(CeedRealloc(index + 1, &ceed_parent->jit_source_roots));
11392b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(path_length + 1, &ceed_parent->jit_source_roots[index]));
1140d602d780SJeremy L Thompson   memcpy(ceed_parent->jit_source_roots[index], jit_source_root, path_length);
11416155f12fSJeremy L Thompson   ceed_parent->num_jit_source_roots++;
1142ee5a26f2SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1143ee5a26f2SJeremy L Thompson }
1144ee5a26f2SJeremy L Thompson 
1145ee5a26f2SJeremy L Thompson /**
1146ca94c3ddSJeremy L Thompson   @brief View a `Ceed`
11470a0da059Sjeremylt 
1148ca94c3ddSJeremy L Thompson   @param[in] ceed   `Ceed` to view
11490a0da059Sjeremylt   @param[in] stream Filestream to write to
11500a0da059Sjeremylt 
11510a0da059Sjeremylt   @return An error code: 0 - success, otherwise - failure
11520a0da059Sjeremylt 
11530a0da059Sjeremylt   @ref User
11540a0da059Sjeremylt **/
11550a0da059Sjeremylt int CeedView(Ceed ceed, FILE *stream) {
1156d1d35e2fSjeremylt   CeedMemType mem_type;
11570a0da059Sjeremylt 
11582b730f8bSJeremy L Thompson   CeedCall(CeedGetPreferredMemType(ceed, &mem_type));
11590a0da059Sjeremylt 
11602b730f8bSJeremy L Thompson   fprintf(stream,
11612b730f8bSJeremy L Thompson           "Ceed\n"
11620a0da059Sjeremylt           "  Ceed Resource: %s\n"
11630a0da059Sjeremylt           "  Preferred MemType: %s\n",
1164d1d35e2fSjeremylt           ceed->resource, CeedMemTypes[mem_type]);
1165e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
11660a0da059Sjeremylt }
11670a0da059Sjeremylt 
11680a0da059Sjeremylt /**
1169ca94c3ddSJeremy L Thompson   @brief Destroy a `Ceed`
1170d7b241e6Sjeremylt 
1171ca94c3ddSJeremy L Thompson   @param[in,out] ceed Address of `Ceed` context to destroy
1172b11c1e72Sjeremylt 
1173b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1174dfdf5a53Sjeremylt 
11757a982d89SJeremy L. Thompson   @ref User
1176b11c1e72Sjeremylt **/
1177d7b241e6Sjeremylt int CeedDestroy(Ceed *ceed) {
1178ad6481ceSJeremy L Thompson   if (!*ceed || --(*ceed)->ref_count > 0) {
1179ad6481ceSJeremy L Thompson     *ceed = NULL;
1180ad6481ceSJeremy L Thompson     return CEED_ERROR_SUCCESS;
1181ad6481ceSJeremy L Thompson   }
11822b730f8bSJeremy L Thompson   if ((*ceed)->delegate) CeedCall(CeedDestroy(&(*ceed)->delegate));
11830ace9bf2Sjeremylt 
1184d1d35e2fSjeremylt   if ((*ceed)->obj_delegate_count > 0) {
118592ae7e47SJeremy L Thompson     for (CeedInt i = 0; i < (*ceed)->obj_delegate_count; i++) {
11862b730f8bSJeremy L Thompson       CeedCall(CeedDestroy(&((*ceed)->obj_delegates[i].delegate)));
11872b730f8bSJeremy L Thompson       CeedCall(CeedFree(&(*ceed)->obj_delegates[i].obj_name));
1188aefd8378Sjeremylt     }
11892b730f8bSJeremy L Thompson     CeedCall(CeedFree(&(*ceed)->obj_delegates));
1190aefd8378Sjeremylt   }
11910ace9bf2Sjeremylt 
11922b730f8bSJeremy L Thompson   if ((*ceed)->Destroy) CeedCall((*ceed)->Destroy(*ceed));
11930ace9bf2Sjeremylt 
119492ae7e47SJeremy L Thompson   for (CeedInt i = 0; i < (*ceed)->num_jit_source_roots; i++) {
11952b730f8bSJeremy L Thompson     CeedCall(CeedFree(&(*ceed)->jit_source_roots[i]));
1196032e71eaSJeremy L Thompson   }
11972b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*ceed)->jit_source_roots));
1198032e71eaSJeremy L Thompson 
11992b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*ceed)->f_offsets));
12002b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*ceed)->resource));
12012b730f8bSJeremy L Thompson   CeedCall(CeedDestroy(&(*ceed)->op_fallback_ceed));
12022b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*ceed)->op_fallback_resource));
12032b730f8bSJeremy L Thompson   CeedCall(CeedFree(ceed));
1204e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1205d7b241e6Sjeremylt }
1206d7b241e6Sjeremylt 
1207f9982c62SWill Pazner // LCOV_EXCL_START
1208f9982c62SWill Pazner const char *CeedErrorFormat(Ceed ceed, const char *format, va_list *args) {
12092b730f8bSJeremy L Thompson   if (ceed->parent) return CeedErrorFormat(ceed->parent, format, args);
12102b730f8bSJeremy L Thompson   if (ceed->op_fallback_parent) return CeedErrorFormat(ceed->op_fallback_parent, format, args);
121178464608Sjeremylt   // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized
121278464608Sjeremylt   vsnprintf(ceed->err_msg, CEED_MAX_RESOURCE_LEN, format, *args);  // NOLINT
1213d1d35e2fSjeremylt   return ceed->err_msg;
1214f9982c62SWill Pazner }
1215f9982c62SWill Pazner // LCOV_EXCL_STOP
1216f9982c62SWill Pazner 
12177a982d89SJeremy L. Thompson /**
1218ca94c3ddSJeremy L Thompson   @brief Error handling implementation; use @ref CeedError() instead.
1219ca94c3ddSJeremy L Thompson 
1220ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
12217a982d89SJeremy L. Thompson 
12227a982d89SJeremy L. Thompson   @ref Developer
12237a982d89SJeremy L. Thompson **/
12242b730f8bSJeremy L Thompson int CeedErrorImpl(Ceed ceed, const char *filename, int lineno, const char *func, int ecode, const char *format, ...) {
12257a982d89SJeremy L. Thompson   va_list args;
1226d1d35e2fSjeremylt   int     ret_val;
12271c66c397SJeremy L Thompson 
12287a982d89SJeremy L. Thompson   va_start(args, format);
12297a982d89SJeremy L. Thompson   if (ceed) {
1230d1d35e2fSjeremylt     ret_val = ceed->Error(ceed, filename, lineno, func, ecode, format, &args);
12317a982d89SJeremy L. Thompson   } else {
1232b0d62198Sjeremylt     // LCOV_EXCL_START
1233477729cfSJeremy L Thompson     const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER");
12342b730f8bSJeremy L Thompson     if (!ceed_error_handler) ceed_error_handler = "abort";
1235bcbe1c99SJeremy L Thompson     if (!strcmp(ceed_error_handler, "return")) {
1236bcbe1c99SJeremy L Thompson       ret_val = CeedErrorReturn(ceed, filename, lineno, func, ecode, format, &args);
1237bcbe1c99SJeremy L Thompson     } else {
1238477729cfSJeremy L Thompson       // This function will not return
1239d1d35e2fSjeremylt       ret_val = CeedErrorAbort(ceed, filename, lineno, func, ecode, format, &args);
12407a982d89SJeremy L. Thompson     }
1241bcbe1c99SJeremy L Thompson   }
12427a982d89SJeremy L. Thompson   va_end(args);
1243d1d35e2fSjeremylt   return ret_val;
1244b0d62198Sjeremylt   // LCOV_EXCL_STOP
12457a982d89SJeremy L. Thompson }
12467a982d89SJeremy L. Thompson 
1247477729cfSJeremy L Thompson /**
1248477729cfSJeremy L Thompson   @brief Error handler that returns without printing anything.
1249477729cfSJeremy L Thompson 
1250ca94c3ddSJeremy L Thompson   Pass this to @ref CeedSetErrorHandler() to obtain this error handling behavior.
1251ca94c3ddSJeremy L Thompson 
1252ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1253477729cfSJeremy L Thompson 
1254477729cfSJeremy L Thompson   @ref Developer
1255477729cfSJeremy L Thompson **/
1256477729cfSJeremy L Thompson // LCOV_EXCL_START
12572b730f8bSJeremy L Thompson int CeedErrorReturn(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) {
1258d1d35e2fSjeremylt   return err_code;
1259477729cfSJeremy L Thompson }
1260477729cfSJeremy L Thompson // LCOV_EXCL_STOP
1261477729cfSJeremy L Thompson 
1262477729cfSJeremy L Thompson /**
1263ea61e9acSJeremy L Thompson   @brief Error handler that stores the error message for future use and returns the error.
1264477729cfSJeremy L Thompson 
1265ca94c3ddSJeremy L Thompson   Pass this to @ref CeedSetErrorHandler() to obtain this error handling behavior.
1266ca94c3ddSJeremy L Thompson 
1267ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1268477729cfSJeremy L Thompson 
1269477729cfSJeremy L Thompson   @ref Developer
1270477729cfSJeremy L Thompson **/
1271477729cfSJeremy L Thompson // LCOV_EXCL_START
12722b730f8bSJeremy L Thompson int CeedErrorStore(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) {
12732b730f8bSJeremy L Thompson   if (ceed->parent) return CeedErrorStore(ceed->parent, filename, line_no, func, err_code, format, args);
12742b730f8bSJeremy L Thompson   if (ceed->op_fallback_parent) return CeedErrorStore(ceed->op_fallback_parent, filename, line_no, func, err_code, format, args);
1275477729cfSJeremy L Thompson 
1276477729cfSJeremy L Thompson   // Build message
12771c66c397SJeremy L Thompson   int len = snprintf(ceed->err_msg, CEED_MAX_RESOURCE_LEN, "%s:%d in %s(): ", filename, line_no, func);
127878464608Sjeremylt   // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized
127978464608Sjeremylt   vsnprintf(ceed->err_msg + len, CEED_MAX_RESOURCE_LEN - len, format, *args);  // NOLINT
1280d1d35e2fSjeremylt   return err_code;
1281477729cfSJeremy L Thompson }
1282477729cfSJeremy L Thompson // LCOV_EXCL_STOP
1283477729cfSJeremy L Thompson 
1284477729cfSJeremy L Thompson /**
1285ca94c3ddSJeremy L Thompson   @brief Error handler that prints to `stderr` and aborts
1286477729cfSJeremy L Thompson 
1287ca94c3ddSJeremy L Thompson   Pass this to @ref CeedSetErrorHandler() to obtain this error handling behavior.
1288ca94c3ddSJeremy L Thompson 
1289ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1290477729cfSJeremy L Thompson 
1291477729cfSJeremy L Thompson   @ref Developer
1292477729cfSJeremy L Thompson **/
1293477729cfSJeremy L Thompson // LCOV_EXCL_START
12942b730f8bSJeremy L Thompson int CeedErrorAbort(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) {
1295d1d35e2fSjeremylt   fprintf(stderr, "%s:%d in %s(): ", filename, line_no, func);
1296f9982c62SWill Pazner   vfprintf(stderr, format, *args);
1297477729cfSJeremy L Thompson   fprintf(stderr, "\n");
1298477729cfSJeremy L Thompson   abort();
1299d1d35e2fSjeremylt   return err_code;
1300477729cfSJeremy L Thompson }
1301477729cfSJeremy L Thompson // LCOV_EXCL_STOP
1302477729cfSJeremy L Thompson 
1303477729cfSJeremy L Thompson /**
1304ca94c3ddSJeremy L Thompson   @brief Error handler that prints to `stderr` and exits.
1305477729cfSJeremy L Thompson 
1306ca94c3ddSJeremy L Thompson   Pass this to @ref CeedSetErrorHandler() to obtain this error handling behavior.
1307477729cfSJeremy L Thompson 
1308ca94c3ddSJeremy L Thompson   In contrast to @ref CeedErrorAbort(), this exits without a signal, so `atexit()` handlers (e.g., as used by gcov) are run.
1309ca94c3ddSJeremy L Thompson 
1310ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1311477729cfSJeremy L Thompson 
1312477729cfSJeremy L Thompson   @ref Developer
1313477729cfSJeremy L Thompson **/
13142b730f8bSJeremy L Thompson int CeedErrorExit(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) {
1315d1d35e2fSjeremylt   fprintf(stderr, "%s:%d in %s(): ", filename, line_no, func);
131678464608Sjeremylt   // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized
131778464608Sjeremylt   vfprintf(stderr, format, *args);  // NOLINT
1318477729cfSJeremy L Thompson   fprintf(stderr, "\n");
1319d1d35e2fSjeremylt   exit(err_code);
1320d1d35e2fSjeremylt   return err_code;
1321477729cfSJeremy L Thompson }
1322477729cfSJeremy L Thompson 
1323477729cfSJeremy L Thompson /**
1324477729cfSJeremy L Thompson   @brief Set error handler
1325477729cfSJeremy L Thompson 
1326ca94c3ddSJeremy L Thompson   A default error handler is set in @ref CeedInit().
1327ca94c3ddSJeremy L Thompson   Use this function to change the error handler to @ref CeedErrorReturn(), @ref CeedErrorAbort(), or a user-defined error handler.
1328ca94c3ddSJeremy L Thompson 
1329ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1330477729cfSJeremy L Thompson 
1331477729cfSJeremy L Thompson   @ref Developer
1332477729cfSJeremy L Thompson **/
1333d1d35e2fSjeremylt int CeedSetErrorHandler(Ceed ceed, CeedErrorHandler handler) {
1334d1d35e2fSjeremylt   ceed->Error = handler;
1335d1d35e2fSjeremylt   if (ceed->delegate) CeedSetErrorHandler(ceed->delegate, handler);
13362b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < ceed->obj_delegate_count; i++) CeedSetErrorHandler(ceed->obj_delegates[i].delegate, handler);
1337e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1338477729cfSJeremy L Thompson }
1339477729cfSJeremy L Thompson 
1340477729cfSJeremy L Thompson /**
1341477729cfSJeremy L Thompson   @brief Get error message
1342477729cfSJeremy L Thompson 
1343ca94c3ddSJeremy L Thompson   The error message is only stored when using the error handler @ref CeedErrorStore()
1344477729cfSJeremy L Thompson 
1345ca94c3ddSJeremy L Thompson   @param[in]  ceed    `Ceed` context to retrieve error message
1346d1d35e2fSjeremylt   @param[out] err_msg Char pointer to hold error message
1347477729cfSJeremy L Thompson 
1348ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1349ca94c3ddSJeremy L Thompson 
1350477729cfSJeremy L Thompson   @ref Developer
1351477729cfSJeremy L Thompson **/
1352d1d35e2fSjeremylt int CeedGetErrorMessage(Ceed ceed, const char **err_msg) {
13532b730f8bSJeremy L Thompson   if (ceed->parent) return CeedGetErrorMessage(ceed->parent, err_msg);
13542b730f8bSJeremy L Thompson   if (ceed->op_fallback_parent) return CeedGetErrorMessage(ceed->op_fallback_parent, err_msg);
1355d1d35e2fSjeremylt   *err_msg = ceed->err_msg;
1356e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1357477729cfSJeremy L Thompson }
1358477729cfSJeremy L Thompson 
1359477729cfSJeremy L Thompson /**
1360ca94c3ddSJeremy L Thompson   @brief Restore error message.
1361477729cfSJeremy L Thompson 
1362ca94c3ddSJeremy L Thompson   The error message is only stored when using the error handler @ref CeedErrorStore().
1363477729cfSJeremy L Thompson 
1364ca94c3ddSJeremy L Thompson   @param[in]  ceed    `Ceed` context to restore error message
1365d1d35e2fSjeremylt   @param[out] err_msg Char pointer that holds error message
1366477729cfSJeremy L Thompson 
1367ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1368ca94c3ddSJeremy L Thompson 
1369477729cfSJeremy L Thompson   @ref Developer
1370477729cfSJeremy L Thompson **/
1371d1d35e2fSjeremylt int CeedResetErrorMessage(Ceed ceed, const char **err_msg) {
13722b730f8bSJeremy L Thompson   if (ceed->parent) return CeedResetErrorMessage(ceed->parent, err_msg);
13732b730f8bSJeremy L Thompson   if (ceed->op_fallback_parent) return CeedResetErrorMessage(ceed->op_fallback_parent, err_msg);
1374d1d35e2fSjeremylt   *err_msg = NULL;
1375d1d35e2fSjeremylt   memcpy(ceed->err_msg, "No error message stored", 24);
1376e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1377477729cfSJeremy L Thompson }
1378477729cfSJeremy L Thompson 
13791070991dSJed Brown /**
1380ca94c3ddSJeremy L Thompson   @brief Get libCEED library version information.
13811070991dSJed Brown 
1382ea61e9acSJeremy L Thompson   libCEED version numbers have the form major.minor.patch.
1383ea61e9acSJeremy L Thompson   Non-release versions may contain unstable interfaces.
13841070991dSJed Brown 
13851070991dSJed Brown   @param[out] major   Major version of the library
13861070991dSJed Brown   @param[out] minor   Minor version of the library
13871070991dSJed Brown   @param[out] patch   Patch (subminor) version of the library
138853cbfc38SJeremy L Thompson   @param[out] release True for releases; false for development branches
13891070991dSJed Brown 
1390ca94c3ddSJeremy L Thompson   The caller may pass `NULL` for any arguments that are not needed.
13911070991dSJed Brown 
1392ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
13931070991dSJed Brown 
13941070991dSJed Brown   @ref Developer
1395ca94c3ddSJeremy L Thompson 
1396ca94c3ddSJeremy L Thompson   @sa CEED_VERSION_GE()
13971070991dSJed Brown */
13981070991dSJed Brown int CeedGetVersion(int *major, int *minor, int *patch, bool *release) {
13991070991dSJed Brown   if (major) *major = CEED_VERSION_MAJOR;
14001070991dSJed Brown   if (minor) *minor = CEED_VERSION_MINOR;
14011070991dSJed Brown   if (patch) *patch = CEED_VERSION_PATCH;
14021070991dSJed Brown   if (release) *release = CEED_VERSION_RELEASE;
1403ca94c3ddSJeremy L Thompson   return CEED_ERROR_SUCCESS;
14041070991dSJed Brown }
14051070991dSJed Brown 
140653cbfc38SJeremy L Thompson /**
140753cbfc38SJeremy L Thompson   @brief Get libCEED scalar type, such as F64 or F32
140853cbfc38SJeremy L Thompson 
140953cbfc38SJeremy L Thompson   @param[out] scalar_type Type of libCEED scalars
141053cbfc38SJeremy L Thompson 
1411ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1412ca94c3ddSJeremy L Thompson 
141353cbfc38SJeremy L Thompson   @ref Developer
141453cbfc38SJeremy L Thompson */
141580a9ef05SNatalie Beams int CeedGetScalarType(CeedScalarType *scalar_type) {
141680a9ef05SNatalie Beams   *scalar_type = CEED_SCALAR_TYPE;
1417ca94c3ddSJeremy L Thompson   return CEED_ERROR_SUCCESS;
141880a9ef05SNatalie Beams }
141980a9ef05SNatalie Beams 
1420d7b241e6Sjeremylt /// @}
1421