xref: /libCEED/interface/ceed.c (revision b0f67a9c1aeeb4d82b4724afaae1227ff4e81f15)
19ba83ac0SJeremy L Thompson // Copyright (c) 2017-2026, 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 
14173501bfeSJeremy L Thompson /**
14273501bfeSJeremy L Thompson   @brief Create a work vector space for a `ceed`
14373501bfeSJeremy L Thompson 
14473501bfeSJeremy L Thompson   @param[in,out] ceed `Ceed` to create work vector space for
14573501bfeSJeremy L Thompson 
14673501bfeSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
14773501bfeSJeremy L Thompson 
14873501bfeSJeremy L Thompson   @ref Developer
14973501bfeSJeremy L Thompson **/
15073501bfeSJeremy L Thompson static int CeedWorkVectorsCreate(Ceed ceed) {
15173501bfeSJeremy L Thompson   CeedCall(CeedCalloc(1, &ceed->work_vectors));
15273501bfeSJeremy L Thompson   return CEED_ERROR_SUCCESS;
15373501bfeSJeremy L Thompson }
15473501bfeSJeremy L Thompson 
15573501bfeSJeremy L Thompson /**
15673501bfeSJeremy L Thompson   @brief Destroy a work vector space for a `ceed`
15773501bfeSJeremy L Thompson 
15873501bfeSJeremy L Thompson   @param[in,out] ceed `Ceed` to destroy work vector space for
15973501bfeSJeremy L Thompson 
16073501bfeSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
16173501bfeSJeremy L Thompson 
16273501bfeSJeremy L Thompson   @ref Developer
16373501bfeSJeremy L Thompson **/
16473501bfeSJeremy L Thompson static int CeedWorkVectorsDestroy(Ceed ceed) {
16573501bfeSJeremy L Thompson   if (!ceed->work_vectors) return CEED_ERROR_SUCCESS;
16673501bfeSJeremy L Thompson   for (CeedSize i = 0; i < ceed->work_vectors->num_vecs; i++) {
16773501bfeSJeremy L Thompson     CeedCheck(!ceed->work_vectors->is_in_use[i], ceed, CEED_ERROR_ACCESS, "Work vector %" CeedSize_FMT " checked out but not returned");
168*b0f67a9cSJeremy L Thompson     // Note: increase ref_count to prevent Ceed destructor from triggering again
169*b0f67a9cSJeremy L Thompson     CeedCall(CeedObjectReference((CeedObject)ceed));
170*b0f67a9cSJeremy L Thompson     CeedCall(CeedObjectReference((CeedObject)ceed));
17173501bfeSJeremy L Thompson     CeedCall(CeedVectorDestroy(&ceed->work_vectors->vecs[i]));
172*b0f67a9cSJeremy L Thompson     // Note: restore ref_count
173*b0f67a9cSJeremy L Thompson     CeedObjectDereference((CeedObject)ceed);
17473501bfeSJeremy L Thompson   }
17573501bfeSJeremy L Thompson   CeedCall(CeedFree(&ceed->work_vectors->is_in_use));
17673501bfeSJeremy L Thompson   CeedCall(CeedFree(&ceed->work_vectors->vecs));
17773501bfeSJeremy L Thompson   CeedCall(CeedFree(&ceed->work_vectors));
17873501bfeSJeremy L Thompson   return CEED_ERROR_SUCCESS;
17973501bfeSJeremy L Thompson }
18073501bfeSJeremy L Thompson 
181*b0f67a9cSJeremy L Thompson /**
182*b0f67a9cSJeremy L Thompson   @brief View a `Ceed` passed as a `CeedObject`
183*b0f67a9cSJeremy L Thompson 
184*b0f67a9cSJeremy L Thompson   @param[in] ceed   `Ceed` to view
185*b0f67a9cSJeremy L Thompson   @param[in] stream Filestream to write to
186*b0f67a9cSJeremy L Thompson 
187*b0f67a9cSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
188*b0f67a9cSJeremy L Thompson 
189*b0f67a9cSJeremy L Thompson   @ref Developer
190*b0f67a9cSJeremy L Thompson **/
191*b0f67a9cSJeremy L Thompson static int CeedView_Object(CeedObject ceed, FILE *stream) {
192*b0f67a9cSJeremy L Thompson   CeedCall(CeedView((Ceed)ceed, stream));
193*b0f67a9cSJeremy L Thompson   return CEED_ERROR_SUCCESS;
194*b0f67a9cSJeremy L Thompson }
195*b0f67a9cSJeremy L Thompson 
1967a982d89SJeremy L. Thompson /// @}
197d7b241e6Sjeremylt 
1987a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
1997a982d89SJeremy L. Thompson /// Ceed Backend API
2007a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
2017a982d89SJeremy L. Thompson /// @addtogroup CeedBackend
2027a982d89SJeremy L. Thompson /// @{
203d7b241e6Sjeremylt 
204b11c1e72Sjeremylt /**
205ca94c3ddSJeremy L Thompson   @brief Return value of `CEED_DEBUG` environment variable
20660f9e2d6SJeremy L Thompson 
207ca94c3ddSJeremy L Thompson   @param[in] ceed `Ceed` context
20860f9e2d6SJeremy L Thompson 
209ca94c3ddSJeremy L Thompson   @return Boolean value: true  - debugging mode enabled
2103f21f6b1SJeremy L Thompson                          false - debugging mode disabled
21160f9e2d6SJeremy L Thompson 
21260f9e2d6SJeremy L Thompson   @ref Backend
21360f9e2d6SJeremy L Thompson **/
214fc6bbcedSJeremy L Thompson // LCOV_EXCL_START
2152b730f8bSJeremy L Thompson bool CeedDebugFlag(const Ceed ceed) { return ceed->is_debug; }
216fc6bbcedSJeremy L Thompson // LCOV_EXCL_STOP
21760f9e2d6SJeremy L Thompson 
21860f9e2d6SJeremy L Thompson /**
219ca94c3ddSJeremy L Thompson   @brief Return value of `CEED_DEBUG` environment variable
22060f9e2d6SJeremy L Thompson 
221ca94c3ddSJeremy L Thompson   @return Boolean value: true  - debugging mode enabled
2223f21f6b1SJeremy L Thompson                          false - debugging mode disabled
2233f21f6b1SJeremy L Thompson 
2243f21f6b1SJeremy L Thompson   @ref Backend
2253f21f6b1SJeremy L Thompson **/
2263f21f6b1SJeremy L Thompson // LCOV_EXCL_START
2271c66c397SJeremy L Thompson bool CeedDebugFlagEnv(void) { return getenv("CEED_DEBUG") || getenv("DEBUG") || getenv("DBG"); }
2283f21f6b1SJeremy L Thompson // LCOV_EXCL_STOP
2293f21f6b1SJeremy L Thompson 
2303f21f6b1SJeremy L Thompson /**
2313f21f6b1SJeremy L Thompson   @brief Print debugging information in color
2323f21f6b1SJeremy L Thompson 
233ca94c3ddSJeremy L Thompson   @param[in] color  Color to print
234ca94c3ddSJeremy L Thompson   @param[in] format Printing format
23560f9e2d6SJeremy L Thompson 
23660f9e2d6SJeremy L Thompson   @ref Backend
23760f9e2d6SJeremy L Thompson **/
238fc6bbcedSJeremy L Thompson // LCOV_EXCL_START
2393f21f6b1SJeremy L Thompson void CeedDebugImpl256(const unsigned char color, const char *format, ...) {
24060f9e2d6SJeremy L Thompson   va_list args;
24160f9e2d6SJeremy L Thompson   va_start(args, format);
24260f9e2d6SJeremy L Thompson   fflush(stdout);
2432b730f8bSJeremy L Thompson   if (color != CEED_DEBUG_COLOR_NONE) fprintf(stdout, "\033[38;5;%dm", color);
24460f9e2d6SJeremy L Thompson   vfprintf(stdout, format, args);
2452b730f8bSJeremy L Thompson   if (color != CEED_DEBUG_COLOR_NONE) fprintf(stdout, "\033[m");
24660f9e2d6SJeremy L Thompson   fprintf(stdout, "\n");
24760f9e2d6SJeremy L Thompson   fflush(stdout);
24860f9e2d6SJeremy L Thompson   va_end(args);
24960f9e2d6SJeremy L Thompson }
250fc6bbcedSJeremy L Thompson // LCOV_EXCL_STOP
25160f9e2d6SJeremy L Thompson 
25260f9e2d6SJeremy L Thompson /**
253ca94c3ddSJeremy L Thompson   @brief Allocate an array on the host; use @ref CeedMalloc().
254b11c1e72Sjeremylt 
255ea61e9acSJeremy L Thompson   Memory usage can be tracked by the library.
256ea61e9acSJeremy L Thompson   This ensures sufficient alignment for vectorization and should be used for large allocations.
257b11c1e72Sjeremylt 
258ea61e9acSJeremy L Thompson   @param[in]  n    Number of units to allocate
259ea61e9acSJeremy L Thompson   @param[in]  unit Size of each unit
260ca94c3ddSJeremy L Thompson   @param[out] p    Address of pointer to hold the result
261b11c1e72Sjeremylt 
262b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
263b11c1e72Sjeremylt 
2647a982d89SJeremy L. Thompson   @ref Backend
265ca94c3ddSJeremy L Thompson 
266ca94c3ddSJeremy L Thompson   @sa CeedFree()
267b11c1e72Sjeremylt **/
268d7b241e6Sjeremylt int CeedMallocArray(size_t n, size_t unit, void *p) {
269d7b241e6Sjeremylt   int ierr = posix_memalign((void **)p, CEED_ALIGN, n * unit);
2706574a04fSJeremy L Thompson   CeedCheck(ierr == 0, NULL, CEED_ERROR_MAJOR, "posix_memalign failed to allocate %zd members of size %zd\n", n, unit);
271e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
272d7b241e6Sjeremylt }
273d7b241e6Sjeremylt 
274b11c1e72Sjeremylt /**
275ca94c3ddSJeremy L Thompson   @brief Allocate a cleared (zeroed) array on the host; use @ref CeedCalloc().
276b11c1e72Sjeremylt 
277b11c1e72Sjeremylt   Memory usage can be tracked by the library.
278b11c1e72Sjeremylt 
279ea61e9acSJeremy L Thompson   @param[in]  n    Number of units to allocate
280ea61e9acSJeremy L Thompson   @param[in]  unit Size of each unit
281ca94c3ddSJeremy L Thompson   @param[out] p    Address of pointer to hold the result
282b11c1e72Sjeremylt 
283b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
284b11c1e72Sjeremylt 
2857a982d89SJeremy L. Thompson   @ref Backend
286ca94c3ddSJeremy L Thompson 
287ca94c3ddSJeremy L Thompson   @sa CeedFree()
288b11c1e72Sjeremylt **/
289d7b241e6Sjeremylt int CeedCallocArray(size_t n, size_t unit, void *p) {
290d7b241e6Sjeremylt   *(void **)p = calloc(n, unit);
2916574a04fSJeremy L Thompson   CeedCheck(!n || !unit || *(void **)p, NULL, CEED_ERROR_MAJOR, "calloc failed to allocate %zd members of size %zd\n", n, unit);
292e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
293d7b241e6Sjeremylt }
294d7b241e6Sjeremylt 
295b11c1e72Sjeremylt /**
296ca94c3ddSJeremy L Thompson   @brief Reallocate an array on the host; use @ref CeedRealloc().
297b11c1e72Sjeremylt 
298b11c1e72Sjeremylt   Memory usage can be tracked by the library.
299b11c1e72Sjeremylt 
300ea61e9acSJeremy L Thompson   @param[in]  n    Number of units to allocate
301ea61e9acSJeremy L Thompson   @param[in]  unit Size of each unit
302ca94c3ddSJeremy L Thompson   @param[out] p    Address of pointer to hold the result
303b11c1e72Sjeremylt 
304b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
305b11c1e72Sjeremylt 
3067a982d89SJeremy L. Thompson   @ref Backend
307ca94c3ddSJeremy L Thompson 
308ca94c3ddSJeremy L Thompson   @sa CeedFree()
309b11c1e72Sjeremylt **/
310d7b241e6Sjeremylt int CeedReallocArray(size_t n, size_t unit, void *p) {
311d7b241e6Sjeremylt   *(void **)p = realloc(*(void **)p, n * unit);
3126574a04fSJeremy L Thompson   CeedCheck(!n || !unit || *(void **)p, NULL, CEED_ERROR_MAJOR, "realloc failed to allocate %zd members of size %zd\n", n, unit);
313e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
314d7b241e6Sjeremylt }
315d7b241e6Sjeremylt 
316f7e22acaSJeremy L Thompson /**
317ca94c3ddSJeremy L Thompson   @brief Allocate a cleared string buffer on the host.
318f7e22acaSJeremy L Thompson 
319f7e22acaSJeremy L Thompson   Memory usage can be tracked by the library.
320f7e22acaSJeremy L Thompson 
321ea61e9acSJeremy L Thompson   @param[in]  source Pointer to string to be copied
322ea61e9acSJeremy L Thompson   @param[out] copy   Pointer to variable to hold newly allocated string copy
323f7e22acaSJeremy L Thompson 
324f7e22acaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
325f7e22acaSJeremy L Thompson 
326f7e22acaSJeremy L Thompson   @ref Backend
327ca94c3ddSJeremy L Thompson 
328ca94c3ddSJeremy L Thompson   @sa CeedFree()
329f7e22acaSJeremy L Thompson **/
330f7e22acaSJeremy L Thompson int CeedStringAllocCopy(const char *source, char **copy) {
331f7e22acaSJeremy L Thompson   size_t len = strlen(source);
3322b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(len + 1, copy));
333d602d780SJeremy L Thompson   memcpy(*copy, source, len);
334f7e22acaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
335f7e22acaSJeremy L Thompson }
336f7e22acaSJeremy L Thompson 
337ca94c3ddSJeremy L Thompson /** Free memory allocated using @ref CeedMalloc() or @ref CeedCalloc()
33834138859Sjeremylt 
339ca94c3ddSJeremy L Thompson   @param[in,out] p Address of pointer to memory.
340ca94c3ddSJeremy 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.
341ca94c3ddSJeremy L Thompson 
342ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
343ca94c3ddSJeremy L Thompson 
344ca94c3ddSJeremy L Thompson   @ref Backend
34534138859Sjeremylt **/
346d7b241e6Sjeremylt int CeedFree(void *p) {
347d7b241e6Sjeremylt   free(*(void **)p);
348d7b241e6Sjeremylt   *(void **)p = NULL;
349e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
350d7b241e6Sjeremylt }
351d7b241e6Sjeremylt 
352f5d1e504SJeremy L Thompson /** Internal helper to manage handoff of user `source_array` to backend with proper @ref CeedCopyMode behavior.
353f5d1e504SJeremy L Thompson 
354f5d1e504SJeremy L Thompson   @param[in]     source_array          Source data provided by user
355f5d1e504SJeremy L Thompson   @param[in]     copy_mode             Copy mode for the data
356f5d1e504SJeremy L Thompson   @param[in]     num_values            Number of values to handle
35717afdf5cSJames Wright   @param[in]     size_unit             Size of array element in bytes
358f5d1e504SJeremy L Thompson   @param[in,out] target_array_owned    Pointer to location to allocated or hold owned data, may be freed if already allocated
359f5d1e504SJeremy L Thompson   @param[out]    target_array_borrowed Pointer to location to hold borrowed data
360f5d1e504SJeremy L Thompson   @param[out]    target_array          Pointer to location for data
361f5d1e504SJeremy L Thompson 
362f5d1e504SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
363f5d1e504SJeremy L Thompson 
364f5d1e504SJeremy L Thompson   @ref Backend
365f5d1e504SJeremy L Thompson **/
366f5d1e504SJeremy L Thompson static inline int CeedSetHostGenericArray(const void *source_array, CeedCopyMode copy_mode, size_t size_unit, CeedSize num_values,
367f5d1e504SJeremy L Thompson                                           void *target_array_owned, void *target_array_borrowed, void *target_array) {
368f5d1e504SJeremy L Thompson   switch (copy_mode) {
369f5d1e504SJeremy L Thompson     case CEED_COPY_VALUES:
370cc3bdf8cSJeremy L Thompson       if (!*(void **)target_array) {
371cc3bdf8cSJeremy L Thompson         if (*(void **)target_array_borrowed) {
372cc3bdf8cSJeremy L Thompson           *(void **)target_array = *(void **)target_array_borrowed;
373cc3bdf8cSJeremy L Thompson         } else {
374f5d1e504SJeremy L Thompson           if (!*(void **)target_array_owned) CeedCall(CeedCallocArray(num_values, size_unit, target_array_owned));
375f5d1e504SJeremy L Thompson           *(void **)target_array = *(void **)target_array_owned;
376cc3bdf8cSJeremy L Thompson         }
377cc3bdf8cSJeremy L Thompson       }
378cc3bdf8cSJeremy L Thompson       if (source_array) memcpy(*(void **)target_array, source_array, size_unit * num_values);
379f5d1e504SJeremy L Thompson       break;
380f5d1e504SJeremy L Thompson     case CEED_OWN_POINTER:
381f5d1e504SJeremy L Thompson       CeedCall(CeedFree(target_array_owned));
382f5d1e504SJeremy L Thompson       *(void **)target_array_owned    = (void *)source_array;
383f5d1e504SJeremy L Thompson       *(void **)target_array_borrowed = NULL;
384f5d1e504SJeremy L Thompson       *(void **)target_array          = *(void **)target_array_owned;
385f5d1e504SJeremy L Thompson       break;
386f5d1e504SJeremy L Thompson     case CEED_USE_POINTER:
387f5d1e504SJeremy L Thompson       CeedCall(CeedFree(target_array_owned));
388f5d1e504SJeremy L Thompson       *(void **)target_array_owned    = NULL;
389f5d1e504SJeremy L Thompson       *(void **)target_array_borrowed = (void *)source_array;
390f5d1e504SJeremy L Thompson       *(void **)target_array          = *(void **)target_array_borrowed;
391f5d1e504SJeremy L Thompson   }
392f5d1e504SJeremy L Thompson   return CEED_ERROR_SUCCESS;
393f5d1e504SJeremy L Thompson }
394f5d1e504SJeremy L Thompson 
395f5d1e504SJeremy L Thompson /** Manage handoff of user `bool` `source_array` to backend with proper @ref CeedCopyMode behavior.
396f5d1e504SJeremy L Thompson 
397f5d1e504SJeremy L Thompson   @param[in]     source_array          Source data provided by user
398f5d1e504SJeremy L Thompson   @param[in]     copy_mode             Copy mode for the data
399f5d1e504SJeremy L Thompson   @param[in]     num_values            Number of values to handle
400f5d1e504SJeremy L Thompson   @param[in,out] target_array_owned    Pointer to location to allocated or hold owned data, may be freed if already allocated
401f5d1e504SJeremy L Thompson   @param[out]    target_array_borrowed Pointer to location to hold borrowed data
402f5d1e504SJeremy L Thompson   @param[out]    target_array          Pointer to location for data
403f5d1e504SJeremy L Thompson 
404f5d1e504SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
405f5d1e504SJeremy L Thompson 
406f5d1e504SJeremy L Thompson   @ref Backend
407f5d1e504SJeremy L Thompson **/
408f5d1e504SJeremy L Thompson int CeedSetHostBoolArray(const bool *source_array, CeedCopyMode copy_mode, CeedSize num_values, const bool **target_array_owned,
409f5d1e504SJeremy L Thompson                          const bool **target_array_borrowed, const bool **target_array) {
410f5d1e504SJeremy L Thompson   CeedCall(CeedSetHostGenericArray(source_array, copy_mode, sizeof(bool), num_values, target_array_owned, target_array_borrowed, target_array));
411f5d1e504SJeremy L Thompson   return CEED_ERROR_SUCCESS;
412f5d1e504SJeremy L Thompson }
413f5d1e504SJeremy L Thompson 
414f5d1e504SJeremy L Thompson /** Manage handoff of user `CeedInt8` `source_array` to backend with proper @ref CeedCopyMode behavior.
415f5d1e504SJeremy L Thompson 
416f5d1e504SJeremy L Thompson   @param[in]     source_array          Source data provided by user
417f5d1e504SJeremy L Thompson   @param[in]     copy_mode             Copy mode for the data
418f5d1e504SJeremy L Thompson   @param[in]     num_values            Number of values to handle
419f5d1e504SJeremy L Thompson   @param[in,out] target_array_owned    Pointer to location to allocated or hold owned data, may be freed if already allocated
420f5d1e504SJeremy L Thompson   @param[out]    target_array_borrowed Pointer to location to hold borrowed data
421f5d1e504SJeremy L Thompson   @param[out]    target_array          Pointer to location for data
422f5d1e504SJeremy L Thompson 
423f5d1e504SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
424f5d1e504SJeremy L Thompson 
425f5d1e504SJeremy L Thompson   @ref Backend
426f5d1e504SJeremy L Thompson **/
427f5d1e504SJeremy L Thompson int CeedSetHostCeedInt8Array(const CeedInt8 *source_array, CeedCopyMode copy_mode, CeedSize num_values, const CeedInt8 **target_array_owned,
428f5d1e504SJeremy L Thompson                              const CeedInt8 **target_array_borrowed, const CeedInt8 **target_array) {
429f5d1e504SJeremy L Thompson   CeedCall(CeedSetHostGenericArray(source_array, copy_mode, sizeof(CeedInt8), num_values, target_array_owned, target_array_borrowed, target_array));
430f5d1e504SJeremy L Thompson   return CEED_ERROR_SUCCESS;
431f5d1e504SJeremy L Thompson }
432f5d1e504SJeremy L Thompson 
433f5d1e504SJeremy L Thompson /** Manage handoff of user `CeedInt` `source_array` to backend with proper @ref CeedCopyMode behavior.
434f5d1e504SJeremy L Thompson 
435f5d1e504SJeremy L Thompson   @param[in]     source_array          Source data provided by user
436f5d1e504SJeremy L Thompson   @param[in]     copy_mode             Copy mode for the data
437f5d1e504SJeremy L Thompson   @param[in]     num_values            Number of values to handle
438f5d1e504SJeremy L Thompson   @param[in,out] target_array_owned    Pointer to location to allocated or hold owned data, may be freed if already allocated
439f5d1e504SJeremy L Thompson   @param[out]    target_array_borrowed Pointer to location to hold borrowed data
440f5d1e504SJeremy L Thompson   @param[out]    target_array          Pointer to location for data
441f5d1e504SJeremy L Thompson 
442f5d1e504SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
443f5d1e504SJeremy L Thompson 
444f5d1e504SJeremy L Thompson   @ref Backend
445f5d1e504SJeremy L Thompson **/
446f5d1e504SJeremy L Thompson int CeedSetHostCeedIntArray(const CeedInt *source_array, CeedCopyMode copy_mode, CeedSize num_values, const CeedInt **target_array_owned,
447f5d1e504SJeremy L Thompson                             const CeedInt **target_array_borrowed, const CeedInt **target_array) {
448f5d1e504SJeremy L Thompson   CeedCall(CeedSetHostGenericArray(source_array, copy_mode, sizeof(CeedInt), num_values, target_array_owned, target_array_borrowed, target_array));
449f5d1e504SJeremy L Thompson   return CEED_ERROR_SUCCESS;
450f5d1e504SJeremy L Thompson }
451f5d1e504SJeremy L Thompson 
452f5d1e504SJeremy L Thompson /** Manage handoff of user `CeedScalar` `source_array` to backend with proper @ref CeedCopyMode behavior.
453f5d1e504SJeremy L Thompson 
454f5d1e504SJeremy L Thompson   @param[in]     source_array          Source data provided by user
455f5d1e504SJeremy L Thompson   @param[in]     copy_mode             Copy mode for the data
456f5d1e504SJeremy L Thompson   @param[in]     num_values            Number of values to handle
457f5d1e504SJeremy L Thompson   @param[in,out] target_array_owned    Pointer to location to allocated or hold owned data, may be freed if already allocated
458f5d1e504SJeremy L Thompson   @param[out]    target_array_borrowed Pointer to location to hold borrowed data
459f5d1e504SJeremy L Thompson   @param[out]    target_array          Pointer to location for data
460f5d1e504SJeremy L Thompson 
461f5d1e504SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
462f5d1e504SJeremy L Thompson 
463f5d1e504SJeremy L Thompson   @ref Backend
464f5d1e504SJeremy L Thompson **/
465f5d1e504SJeremy L Thompson int CeedSetHostCeedScalarArray(const CeedScalar *source_array, CeedCopyMode copy_mode, CeedSize num_values, const CeedScalar **target_array_owned,
466f5d1e504SJeremy L Thompson                                const CeedScalar **target_array_borrowed, const CeedScalar **target_array) {
467f5d1e504SJeremy L Thompson   CeedCall(CeedSetHostGenericArray(source_array, copy_mode, sizeof(CeedScalar), num_values, target_array_owned, target_array_borrowed, target_array));
468f5d1e504SJeremy L Thompson   return CEED_ERROR_SUCCESS;
469f5d1e504SJeremy L Thompson }
470f5d1e504SJeremy L Thompson 
471d7b241e6Sjeremylt /**
472ca94c3ddSJeremy L Thompson   @brief Register a `Ceed` backend
473d7b241e6Sjeremylt 
474ea61e9acSJeremy L Thompson   @param[in] prefix   Prefix of resources for this backend to respond to.
475ea61e9acSJeremy L Thompson                         For example, the reference backend responds to "/cpu/self".
476ca94c3ddSJeremy L Thompson   @param[in] init     Initialization function called by @ref CeedInit() when the backend is selected to drive the requested resource
477ea61e9acSJeremy L Thompson   @param[in] priority Integer priority.
478ca94c3ddSJeremy L Thompson                         Lower values are preferred in case the resource requested by @ref CeedInit() has non-unique best prefix match.
479b11c1e72Sjeremylt 
480b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
481dfdf5a53Sjeremylt 
4827a982d89SJeremy L. Thompson   @ref Backend
483b11c1e72Sjeremylt **/
4842b730f8bSJeremy L Thompson int CeedRegister(const char *prefix, int (*init)(const char *, Ceed), unsigned int priority) {
48510243053SJeremy L Thompson   CeedDebugEnv("Backend Register: %s", prefix);
4866a406739SJeremy L Thompson   CeedRegisterImpl(prefix, init, priority);
487e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
488d7b241e6Sjeremylt }
489d7b241e6Sjeremylt 
490b11c1e72Sjeremylt /**
49160f9e2d6SJeremy L Thompson   @brief Return debugging status flag
49260f9e2d6SJeremy L Thompson 
493ca94c3ddSJeremy L Thompson   @param[in]  ceed     `Ceed` context to get debugging flag
494ea61e9acSJeremy L Thompson   @param[out] is_debug Variable to store debugging flag
49560f9e2d6SJeremy L Thompson 
49660f9e2d6SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
49760f9e2d6SJeremy L Thompson 
498d1d35e2fSjeremylt   @ref Backend
49960f9e2d6SJeremy L Thompson **/
500d1d35e2fSjeremylt int CeedIsDebug(Ceed ceed, bool *is_debug) {
5013f21f6b1SJeremy L Thompson   *is_debug = ceed->is_debug;
502e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
50360f9e2d6SJeremy L Thompson }
50460f9e2d6SJeremy L Thompson 
50560f9e2d6SJeremy L Thompson /**
506bf84744cSJeremy L Thompson   @brief Get the root of the requested resource.
507bf84744cSJeremy L Thompson 
508bf84744cSJeremy L Thompson   Note: Caller is responsible for calling @ref CeedFree() on the `resource_root`.
509bc246734SJeremy L Thompson 
510ca94c3ddSJeremy L Thompson   @param[in]  ceed          `Ceed` context to get resource name of
511ca94c3ddSJeremy L Thompson   @param[in]  resource      Full user specified resource
512ca94c3ddSJeremy L Thompson   @param[in]  delineator    Delineator to break `resource_root` and `resource_spec`
513bc246734SJeremy L Thompson   @param[out] resource_root Variable to store resource root
514bc246734SJeremy L Thompson 
515bc246734SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
516bc246734SJeremy L Thompson 
517bc246734SJeremy L Thompson   @ref Backend
518bc246734SJeremy L Thompson **/
519bc246734SJeremy L Thompson int CeedGetResourceRoot(Ceed ceed, const char *resource, const char *delineator, char **resource_root) {
520bc246734SJeremy L Thompson   char  *device_spec       = strstr(resource, delineator);
521bc246734SJeremy L Thompson   size_t resource_root_len = device_spec ? (size_t)(device_spec - resource) + 1 : strlen(resource) + 1;
5221c66c397SJeremy L Thompson 
523bc246734SJeremy L Thompson   CeedCall(CeedCalloc(resource_root_len, resource_root));
524bc246734SJeremy L Thompson   memcpy(*resource_root, resource, resource_root_len - 1);
525bc246734SJeremy L Thompson   return CEED_ERROR_SUCCESS;
526bc246734SJeremy L Thompson }
527bc246734SJeremy L Thompson 
528bc246734SJeremy L Thompson /**
529ca94c3ddSJeremy L Thompson   @brief Retrieve a parent `Ceed` context
5307a982d89SJeremy L. Thompson 
531ca94c3ddSJeremy L Thompson   @param[in]  ceed   `Ceed` context to retrieve parent of
5327a982d89SJeremy L. Thompson   @param[out] parent Address to save the parent to
5337a982d89SJeremy L. Thompson 
5347a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5357a982d89SJeremy L. Thompson 
5367a982d89SJeremy L. Thompson   @ref Backend
5377a982d89SJeremy L. Thompson **/
5387a982d89SJeremy L. Thompson int CeedGetParent(Ceed ceed, Ceed *parent) {
5397a982d89SJeremy L. Thompson   if (ceed->parent) {
5402b730f8bSJeremy L Thompson     CeedCall(CeedGetParent(ceed->parent, parent));
541e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
5427a982d89SJeremy L. Thompson   }
5439bc66399SJeremy L Thompson   *parent = NULL;
5449bc66399SJeremy L Thompson   CeedCall(CeedReferenceCopy(ceed, parent));
545e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5467a982d89SJeremy L. Thompson }
5477a982d89SJeremy L. Thompson 
5487a982d89SJeremy L. Thompson /**
549ca94c3ddSJeremy L Thompson   @brief Retrieve a delegate `Ceed` context
5507a982d89SJeremy L. Thompson 
551ca94c3ddSJeremy L Thompson   @param[in]  ceed     `Ceed` context to retrieve delegate of
5527a982d89SJeremy L. Thompson   @param[out] delegate Address to save the delegate to
5537a982d89SJeremy L. Thompson 
5547a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5557a982d89SJeremy L. Thompson 
5567a982d89SJeremy L. Thompson   @ref Backend
5577a982d89SJeremy L. Thompson **/
5587a982d89SJeremy L. Thompson int CeedGetDelegate(Ceed ceed, Ceed *delegate) {
5599bc66399SJeremy L Thompson   *delegate = NULL;
5609bc66399SJeremy L Thompson   if (ceed->delegate) CeedCall(CeedReferenceCopy(ceed->delegate, delegate));
561e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5627a982d89SJeremy L. Thompson }
5637a982d89SJeremy L. Thompson 
5647a982d89SJeremy L. Thompson /**
565ca94c3ddSJeremy L Thompson   @brief Set a delegate `Ceed` context
5667a982d89SJeremy L. Thompson 
567ca94c3ddSJeremy L Thompson   This function allows a `Ceed` context to set a delegate `Ceed` context.
568ca94c3ddSJeremy L Thompson   All backend implementations default to the delegate `Ceed` context, unless overridden.
5697a982d89SJeremy L. Thompson 
570ca94c3ddSJeremy L Thompson   @param[in]  ceed     `Ceed` context to set delegate of
5717a982d89SJeremy L. Thompson   @param[out] delegate Address to set the delegate to
5727a982d89SJeremy L. Thompson 
5737a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5747a982d89SJeremy L. Thompson 
5757a982d89SJeremy L. Thompson   @ref Backend
5767a982d89SJeremy L. Thompson **/
5777a982d89SJeremy L. Thompson int CeedSetDelegate(Ceed ceed, Ceed delegate) {
5789bc66399SJeremy L Thompson   CeedCall(CeedReferenceCopy(delegate, &ceed->delegate));
5797a982d89SJeremy L. Thompson   delegate->parent = ceed;
580e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5817a982d89SJeremy L. Thompson }
5827a982d89SJeremy L. Thompson 
5837a982d89SJeremy L. Thompson /**
584ca94c3ddSJeremy L Thompson   @brief Retrieve a delegate `Ceed` context for a specific object type
5857a982d89SJeremy L. Thompson 
586ca94c3ddSJeremy L Thompson   @param[in]  ceed     `Ceed` context to retrieve delegate of
5877a982d89SJeremy L. Thompson   @param[out] delegate Address to save the delegate to
588d1d35e2fSjeremylt   @param[in]  obj_name Name of the object type to retrieve delegate for
5897a982d89SJeremy L. Thompson 
5907a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5917a982d89SJeremy L. Thompson 
5927a982d89SJeremy L. Thompson   @ref Backend
5937a982d89SJeremy L. Thompson **/
594d1d35e2fSjeremylt int CeedGetObjectDelegate(Ceed ceed, Ceed *delegate, const char *obj_name) {
5957a982d89SJeremy L. Thompson   // Check for object delegate
5962b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < ceed->obj_delegate_count; i++) {
597d1d35e2fSjeremylt     if (!strcmp(obj_name, ceed->obj_delegates->obj_name)) {
5989bc66399SJeremy L Thompson       *delegate = NULL;
5999bc66399SJeremy L Thompson       CeedCall(CeedReferenceCopy(ceed->obj_delegates->delegate, delegate));
600e15f9bd0SJeremy L Thompson       return CEED_ERROR_SUCCESS;
6017a982d89SJeremy L. Thompson     }
6022b730f8bSJeremy L Thompson   }
6037a982d89SJeremy L. Thompson 
6047a982d89SJeremy L. Thompson   // Use default delegate if no object delegate
6052b730f8bSJeremy L Thompson   CeedCall(CeedGetDelegate(ceed, delegate));
606e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6077a982d89SJeremy L. Thompson }
6087a982d89SJeremy L. Thompson 
6097a982d89SJeremy L. Thompson /**
610ca94c3ddSJeremy L Thompson   @brief Set a delegate `Ceed` context for a specific object type
6117a982d89SJeremy L. Thompson 
612ca94c3ddSJeremy L Thompson   This function allows a `Ceed` context to set a delegate `Ceed` context for a given type of `Ceed` object.
613ca94c3ddSJeremy L Thompson   All backend implementations default to the delegate `Ceed` context for this object.
614ca94c3ddSJeremy L Thompson   For example, `CeedSetObjectDelegate(ceed, delegate, "Basis")` uses delegate implementations for all `CeedBasis` backend functions.
6157a982d89SJeremy L. Thompson 
616ca94c3ddSJeremy L Thompson   @param[in,out] ceed     `Ceed` context to set delegate of
617ca94c3ddSJeremy L Thompson   @param[in]     delegate `Ceed` context to use for delegation
618d1d35e2fSjeremylt   @param[in]     obj_name Name of the object type to set delegate for
6197a982d89SJeremy L. Thompson 
6207a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6217a982d89SJeremy L. Thompson 
6227a982d89SJeremy L. Thompson   @ref Backend
6237a982d89SJeremy L. Thompson **/
624d1d35e2fSjeremylt int CeedSetObjectDelegate(Ceed ceed, Ceed delegate, const char *obj_name) {
625d1d35e2fSjeremylt   CeedInt count = ceed->obj_delegate_count;
6267a982d89SJeremy L. Thompson 
6277a982d89SJeremy L. Thompson   // Malloc or Realloc
6287a982d89SJeremy L. Thompson   if (count) {
6292b730f8bSJeremy L Thompson     CeedCall(CeedRealloc(count + 1, &ceed->obj_delegates));
6307a982d89SJeremy L. Thompson   } else {
6312b730f8bSJeremy L Thompson     CeedCall(CeedCalloc(1, &ceed->obj_delegates));
6327a982d89SJeremy L. Thompson   }
633d1d35e2fSjeremylt   ceed->obj_delegate_count++;
6347a982d89SJeremy L. Thompson 
6357a982d89SJeremy L. Thompson   // Set object delegate
6369bc66399SJeremy L Thompson   CeedCall(CeedReferenceCopy(delegate, &ceed->obj_delegates[count].delegate));
6372b730f8bSJeremy L Thompson   CeedCall(CeedStringAllocCopy(obj_name, &ceed->obj_delegates[count].obj_name));
6387a982d89SJeremy L. Thompson 
6397a982d89SJeremy L. Thompson   // Set delegate parent
6407a982d89SJeremy L. Thompson   delegate->parent = ceed;
641e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6427a982d89SJeremy L. Thompson }
6437a982d89SJeremy L. Thompson 
6447a982d89SJeremy L. Thompson /**
645ca94c3ddSJeremy L Thompson   @brief Get the fallback `Ceed` for `CeedOperator`
6468687e1d4SJeremy L Thompson 
647ca94c3ddSJeremy L Thompson   @param[in]  ceed          `Ceed` context
648ca94c3ddSJeremy L Thompson   @param[out] fallback_ceed Variable to store fallback `Ceed`
6498687e1d4SJeremy L Thompson 
6508687e1d4SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
6518687e1d4SJeremy L Thompson 
6528687e1d4SJeremy L Thompson   @ref Backend
6538687e1d4SJeremy L Thompson **/
6548687e1d4SJeremy L Thompson int CeedGetOperatorFallbackCeed(Ceed ceed, Ceed *fallback_ceed) {
65546b50f9eSZach Atkins   if (ceed->op_fallback_ceed) {
656ca38d01dSJeremy L Thompson     CeedDebug256(ceed, CEED_DEBUG_COLOR_SUCCESS, "---------- Ceed Fallback ----------\n");
65746b50f9eSZach Atkins     CeedDebug(ceed, "Falling back from Ceed with backend %s at address %p to Ceed with backend %s at address %p", ceed->resource, ceed,
65846b50f9eSZach Atkins               ceed->op_fallback_ceed->resource, ceed->op_fallback_ceed);
659d04bbc78SJeremy L Thompson   }
6608687e1d4SJeremy L Thompson 
6619bc66399SJeremy L Thompson   *fallback_ceed = NULL;
6629bc66399SJeremy L Thompson   if (ceed->op_fallback_ceed) CeedCall(CeedReferenceCopy(ceed->op_fallback_ceed, fallback_ceed));
6638687e1d4SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6648687e1d4SJeremy L Thompson }
6658687e1d4SJeremy L Thompson 
6668687e1d4SJeremy L Thompson /**
667ca94c3ddSJeremy L Thompson   @brief Set the fallback resource for `CeedOperator`.
6684385fb7fSSebastian Grimberg 
66946b50f9eSZach Atkins   The current fallback, if any, is freed by calling this function.
6707a982d89SJeremy L. Thompson 
671ca94c3ddSJeremy L Thompson   @param[in,out] ceed          `Ceed` context
67246b50f9eSZach Atkins   @param[in]     fallback_ceed `Ceed` context to create fallback operators
6737a982d89SJeremy L. Thompson 
6747a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6757a982d89SJeremy L. Thompson 
6767a982d89SJeremy L. Thompson   @ref Backend
6777a982d89SJeremy L. Thompson **/
67846b50f9eSZach Atkins int CeedSetOperatorFallbackCeed(Ceed ceed, Ceed fallback_ceed) {
67946b50f9eSZach Atkins   CeedCall(CeedReferenceCopy(fallback_ceed, &ceed->op_fallback_ceed));
68046b50f9eSZach Atkins   fallback_ceed->parent = ceed;
681e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6827a982d89SJeremy L. Thompson }
6837a982d89SJeremy L. Thompson 
6847a982d89SJeremy L. Thompson /**
685ca94c3ddSJeremy L Thompson   @brief Flag `Ceed` context as deterministic
6869525855cSJeremy L Thompson 
687ca94c3ddSJeremy L Thompson   @param[in]  ceed             `Ceed` to flag as deterministic
68896b902e2Sjeremylt   @param[out] is_deterministic Deterministic status to set
6899525855cSJeremy L Thompson 
6909525855cSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
6919525855cSJeremy L Thompson 
6929525855cSJeremy L Thompson   @ref Backend
6939525855cSJeremy L Thompson **/
694d1d35e2fSjeremylt int CeedSetDeterministic(Ceed ceed, bool is_deterministic) {
695d1d35e2fSjeremylt   ceed->is_deterministic = is_deterministic;
696e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6979525855cSJeremy L Thompson }
6989525855cSJeremy L Thompson 
6999525855cSJeremy L Thompson /**
700ca94c3ddSJeremy L Thompson   @brief Set a backend function.
7017a982d89SJeremy L. Thompson 
702ea61e9acSJeremy L Thompson   This function is used for a backend to set the function associated with the Ceed objects.
703ca94c3ddSJeremy 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().
7049fd66db6SSebastian Grimberg   Note, the prefix 'Ceed' is not required for the object type ("Basis" vs "CeedBasis").
7057a982d89SJeremy L. Thompson 
706ca94c3ddSJeremy L Thompson   @param[in]  ceed      `Ceed` context for error handling
707ea61e9acSJeremy L Thompson   @param[in]  type      Type of Ceed object to set function for
7087a982d89SJeremy L. Thompson   @param[out] object    Ceed object to set function for
709ea61e9acSJeremy L Thompson   @param[in]  func_name Name of function to set
710ea61e9acSJeremy L Thompson   @param[in]  f         Function to set
7117a982d89SJeremy L. Thompson 
7127a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7137a982d89SJeremy L. Thompson 
7147a982d89SJeremy L. Thompson   @ref Backend
7157a982d89SJeremy L. Thompson **/
716897d4737SSebastian Grimberg int CeedSetBackendFunctionImpl(Ceed ceed, const char *type, void *object, const char *func_name, void (*f)(void)) {
717d1d35e2fSjeremylt   char lookup_name[CEED_MAX_RESOURCE_LEN + 1] = "";
7187a982d89SJeremy L. Thompson 
7197a982d89SJeremy L. Thompson   // Build lookup name
7202b730f8bSJeremy L Thompson   if (strcmp(type, "Ceed")) strncat(lookup_name, "Ceed", CEED_MAX_RESOURCE_LEN);
721d1d35e2fSjeremylt   strncat(lookup_name, type, CEED_MAX_RESOURCE_LEN);
722d1d35e2fSjeremylt   strncat(lookup_name, func_name, CEED_MAX_RESOURCE_LEN);
7237a982d89SJeremy L. Thompson 
7247a982d89SJeremy L. Thompson   // Find and use offset
7252b730f8bSJeremy L Thompson   for (CeedInt i = 0; ceed->f_offsets[i].func_name; i++) {
726d1d35e2fSjeremylt     if (!strcmp(ceed->f_offsets[i].func_name, lookup_name)) {
727d1d35e2fSjeremylt       size_t offset          = ceed->f_offsets[i].offset;
7287a982d89SJeremy L. Thompson       int (**fpointer)(void) = (int (**)(void))((char *)object + offset);  // *NOPAD*
7291c66c397SJeremy L Thompson 
730897d4737SSebastian Grimberg       *fpointer = (int (*)(void))f;
731e15f9bd0SJeremy L Thompson       return CEED_ERROR_SUCCESS;
7327a982d89SJeremy L. Thompson     }
7332b730f8bSJeremy L Thompson   }
7347a982d89SJeremy L. Thompson 
7357a982d89SJeremy L. Thompson   // LCOV_EXCL_START
7362b730f8bSJeremy L Thompson   return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Requested function '%s' was not found for CEED object '%s'", func_name, type);
7377a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
7387a982d89SJeremy L. Thompson }
7397a982d89SJeremy L. Thompson 
7407a982d89SJeremy L. Thompson /**
741ca94c3ddSJeremy L Thompson   @brief Retrieve backend data for a `Ceed` context
7427a982d89SJeremy L. Thompson 
743ca94c3ddSJeremy L Thompson   @param[in]  ceed `Ceed` context to retrieve data of
7447a982d89SJeremy L. Thompson   @param[out] data Address to save data to
7457a982d89SJeremy L. Thompson 
7467a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7477a982d89SJeremy L. Thompson 
7487a982d89SJeremy L. Thompson   @ref Backend
7497a982d89SJeremy L. Thompson **/
750777ff853SJeremy L Thompson int CeedGetData(Ceed ceed, void *data) {
751777ff853SJeremy L Thompson   *(void **)data = ceed->data;
752e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7537a982d89SJeremy L. Thompson }
7547a982d89SJeremy L. Thompson 
7557a982d89SJeremy L. Thompson /**
756ca94c3ddSJeremy L Thompson   @brief Set backend data for a `Ceed` context
7577a982d89SJeremy L. Thompson 
758ca94c3ddSJeremy L Thompson   @param[in,out] ceed `Ceed` context to set data of
759ea61e9acSJeremy L Thompson   @param[in]     data Address of data to set
7607a982d89SJeremy L. Thompson 
7617a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7627a982d89SJeremy L. Thompson 
7637a982d89SJeremy L. Thompson   @ref Backend
7647a982d89SJeremy L. Thompson **/
765777ff853SJeremy L Thompson int CeedSetData(Ceed ceed, void *data) {
766777ff853SJeremy L Thompson   ceed->data = data;
767e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7687a982d89SJeremy L. Thompson }
7697a982d89SJeremy L. Thompson 
77034359f16Sjeremylt /**
771ca94c3ddSJeremy L Thompson   @brief Increment the reference counter for a `Ceed` context
77234359f16Sjeremylt 
773ca94c3ddSJeremy L Thompson   @param[in,out] ceed `Ceed` context to increment the reference counter
77434359f16Sjeremylt 
77534359f16Sjeremylt   @return An error code: 0 - success, otherwise - failure
77634359f16Sjeremylt 
77734359f16Sjeremylt   @ref Backend
77834359f16Sjeremylt **/
7799560d06aSjeremylt int CeedReference(Ceed ceed) {
780*b0f67a9cSJeremy L Thompson   CeedCall(CeedObjectReference((CeedObject)ceed));
78134359f16Sjeremylt   return CEED_ERROR_SUCCESS;
78234359f16Sjeremylt }
78334359f16Sjeremylt 
78473501bfeSJeremy L Thompson /**
7850b37c066SZach Atkins   @brief Computes the current memory usage of the work vectors in a `Ceed` context and prints to debug.abort
7860b37c066SZach Atkins 
7870b37c066SZach Atkins   @param[in]  ceed     `Ceed` context
788ec4241e6SJeremy L Thompson   @param[out] usage_mb Address of the variable where the MB of work vector usage will be stored
7890b37c066SZach Atkins 
7900b37c066SZach Atkins   @return An error code: 0 - success, otherwise - failure
7910b37c066SZach Atkins 
7920b37c066SZach Atkins   @ref Developer
7930b37c066SZach Atkins **/
79455326fe7SZach Atkins int CeedGetWorkVectorMemoryUsage(Ceed ceed, CeedScalar *usage_mb) {
795fd326ce8SZach Atkins   if (!ceed->VectorCreate) {
796fd326ce8SZach Atkins     Ceed delegate;
797fd326ce8SZach Atkins 
798fd326ce8SZach Atkins     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Vector"));
799fd326ce8SZach Atkins     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement VectorCreate");
800fd326ce8SZach Atkins     CeedCall(CeedGetWorkVectorMemoryUsage(delegate, usage_mb));
801fd326ce8SZach Atkins     CeedCall(CeedDestroy(&delegate));
802fd326ce8SZach Atkins     return CEED_ERROR_SUCCESS;
803fd326ce8SZach Atkins   }
80455326fe7SZach Atkins   *usage_mb = 0.0;
8050b37c066SZach Atkins   if (ceed->work_vectors) {
8060b37c066SZach Atkins     for (CeedInt i = 0; i < ceed->work_vectors->num_vecs; i++) {
8070b37c066SZach Atkins       CeedSize vec_len;
8080b37c066SZach Atkins       CeedCall(CeedVectorGetLength(ceed->work_vectors->vecs[i], &vec_len));
80955326fe7SZach Atkins       *usage_mb += vec_len;
8100b37c066SZach Atkins     }
81155326fe7SZach Atkins     *usage_mb *= sizeof(CeedScalar) * 1e-6;
81255326fe7SZach Atkins     CeedDebug(ceed, "Resource {%s}: Work vectors memory usage: %" CeedInt_FMT " vectors, %g MB\n", ceed->resource, ceed->work_vectors->num_vecs,
81355326fe7SZach Atkins               *usage_mb);
8140b37c066SZach Atkins   }
8150b37c066SZach Atkins   return CEED_ERROR_SUCCESS;
8160b37c066SZach Atkins }
8170b37c066SZach Atkins 
8180b37c066SZach Atkins /**
8190b37c066SZach Atkins   @brief Clear inactive work vectors in a `Ceed` context below a minimum length.
8200b37c066SZach Atkins 
8210b37c066SZach Atkins   @param[in,out] ceed    `Ceed` context
8220b37c066SZach Atkins   @param[in]     min_len Minimum length of work vector to keep
8230b37c066SZach Atkins 
8240b37c066SZach Atkins   @return An error code: 0 - success, otherwise - failure
8250b37c066SZach Atkins 
8260b37c066SZach Atkins   @ref Backend
8270b37c066SZach Atkins **/
8280b37c066SZach Atkins int CeedClearWorkVectors(Ceed ceed, CeedSize min_len) {
829fd326ce8SZach Atkins   if (!ceed->VectorCreate) {
830fd326ce8SZach Atkins     Ceed delegate;
831fd326ce8SZach Atkins 
832fd326ce8SZach Atkins     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Vector"));
833fd326ce8SZach Atkins     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement VectorCreate");
834fd326ce8SZach Atkins     CeedCall(CeedClearWorkVectors(delegate, min_len));
835fd326ce8SZach Atkins     CeedCall(CeedDestroy(&delegate));
836fd326ce8SZach Atkins     return CEED_ERROR_SUCCESS;
837fd326ce8SZach Atkins   }
8380b37c066SZach Atkins   if (!ceed->work_vectors) return CEED_ERROR_SUCCESS;
8390b37c066SZach Atkins   for (CeedInt i = 0; i < ceed->work_vectors->num_vecs; i++) {
8400b37c066SZach Atkins     if (ceed->work_vectors->is_in_use[i]) continue;
8410b37c066SZach Atkins     CeedSize vec_len;
8420b37c066SZach Atkins     CeedCall(CeedVectorGetLength(ceed->work_vectors->vecs[i], &vec_len));
8430b37c066SZach Atkins     if (vec_len < min_len) {
844*b0f67a9cSJeremy L Thompson       // Note: increase ref_count to prevent Ceed destructor from triggering
845*b0f67a9cSJeremy L Thompson       CeedCall(CeedObjectReference((CeedObject)ceed));
846*b0f67a9cSJeremy L Thompson       CeedCall(CeedObjectReference((CeedObject)ceed));
8470b37c066SZach Atkins       CeedCall(CeedVectorDestroy(&ceed->work_vectors->vecs[i]));
848*b0f67a9cSJeremy L Thompson       // Note: restore ref_count
849*b0f67a9cSJeremy L Thompson       CeedObjectDereference((CeedObject)ceed);
8500b37c066SZach Atkins       ceed->work_vectors->num_vecs--;
8510b37c066SZach Atkins       if (ceed->work_vectors->num_vecs > 0) {
8520b37c066SZach Atkins         ceed->work_vectors->vecs[i]                                 = ceed->work_vectors->vecs[ceed->work_vectors->num_vecs];
8530b37c066SZach Atkins         ceed->work_vectors->is_in_use[i]                            = ceed->work_vectors->is_in_use[ceed->work_vectors->num_vecs];
8540b37c066SZach Atkins         ceed->work_vectors->is_in_use[ceed->work_vectors->num_vecs] = false;
8550b37c066SZach Atkins         i--;
8560b37c066SZach Atkins       }
8570b37c066SZach Atkins     }
8580b37c066SZach Atkins   }
8590b37c066SZach Atkins   return CEED_ERROR_SUCCESS;
8600b37c066SZach Atkins }
8610b37c066SZach Atkins 
8620b37c066SZach Atkins /**
86373501bfeSJeremy L Thompson   @brief Get a `CeedVector` for scratch work from a `Ceed` context.
86473501bfeSJeremy L Thompson 
86573501bfeSJeremy L Thompson   Note: This vector must be restored with @ref CeedRestoreWorkVector().
86673501bfeSJeremy L Thompson 
86773501bfeSJeremy L Thompson   @param[in]  ceed `Ceed` context
86873501bfeSJeremy L Thompson   @param[in]  len  Minimum length of work vector
86973501bfeSJeremy L Thompson   @param[out] vec  Address of the variable where `CeedVector` will be stored
87073501bfeSJeremy L Thompson 
87173501bfeSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
87273501bfeSJeremy L Thompson 
87373501bfeSJeremy L Thompson   @ref Backend
87473501bfeSJeremy L Thompson **/
87573501bfeSJeremy L Thompson int CeedGetWorkVector(Ceed ceed, CeedSize len, CeedVector *vec) {
87673501bfeSJeremy L Thompson   CeedInt    i = 0;
87755326fe7SZach Atkins   CeedScalar usage_mb;
87873501bfeSJeremy L Thompson 
879fd326ce8SZach Atkins   if (!ceed->VectorCreate) {
880fd326ce8SZach Atkins     Ceed delegate;
881fd326ce8SZach Atkins 
882fd326ce8SZach Atkins     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Vector"));
883fd326ce8SZach Atkins     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement VectorCreate");
884fd326ce8SZach Atkins     CeedCall(CeedGetWorkVector(delegate, len, vec));
885fd326ce8SZach Atkins     CeedCall(CeedDestroy(&delegate));
886fd326ce8SZach Atkins     return CEED_ERROR_SUCCESS;
887fd326ce8SZach Atkins   }
888fd326ce8SZach Atkins 
88973501bfeSJeremy L Thompson   if (!ceed->work_vectors) CeedCall(CeedWorkVectorsCreate(ceed));
89073501bfeSJeremy L Thompson 
89173501bfeSJeremy L Thompson   // Search for big enough work vector
89273501bfeSJeremy L Thompson   for (i = 0; i < ceed->work_vectors->num_vecs; i++) {
89373501bfeSJeremy L Thompson     if (!ceed->work_vectors->is_in_use[i]) {
89473501bfeSJeremy L Thompson       CeedSize work_len;
89573501bfeSJeremy L Thompson 
89673501bfeSJeremy L Thompson       CeedCall(CeedVectorGetLength(ceed->work_vectors->vecs[i], &work_len));
89773501bfeSJeremy L Thompson       if (work_len >= len) break;
89873501bfeSJeremy L Thompson     }
89973501bfeSJeremy L Thompson   }
90073501bfeSJeremy L Thompson   // Long enough vector was not found
90173501bfeSJeremy L Thompson   if (i == ceed->work_vectors->num_vecs) {
90273501bfeSJeremy L Thompson     if (ceed->work_vectors->max_vecs == 0) {
90373501bfeSJeremy L Thompson       ceed->work_vectors->max_vecs = 1;
90473501bfeSJeremy L Thompson       CeedCall(CeedCalloc(ceed->work_vectors->max_vecs, &ceed->work_vectors->vecs));
90573501bfeSJeremy L Thompson       CeedCall(CeedCalloc(ceed->work_vectors->max_vecs, &ceed->work_vectors->is_in_use));
90673501bfeSJeremy L Thompson     } else if (ceed->work_vectors->max_vecs == i) {
90773501bfeSJeremy L Thompson       ceed->work_vectors->max_vecs *= 2;
90873501bfeSJeremy L Thompson       CeedCall(CeedRealloc(ceed->work_vectors->max_vecs, &ceed->work_vectors->vecs));
90973501bfeSJeremy L Thompson       CeedCall(CeedRealloc(ceed->work_vectors->max_vecs, &ceed->work_vectors->is_in_use));
91073501bfeSJeremy L Thompson     }
91173501bfeSJeremy L Thompson     ceed->work_vectors->num_vecs++;
91273501bfeSJeremy L Thompson     CeedCallBackend(CeedVectorCreate(ceed, len, &ceed->work_vectors->vecs[i]));
913*b0f67a9cSJeremy L Thompson     // Note: ref_count manipulation to prevent a ref-loop
914*b0f67a9cSJeremy L Thompson     CeedObjectDereference((CeedObject)ceed);
91555326fe7SZach Atkins     if (ceed->is_debug) CeedGetWorkVectorMemoryUsage(ceed, &usage_mb);
91673501bfeSJeremy L Thompson   }
91773501bfeSJeremy L Thompson   // Return pointer to work vector
91873501bfeSJeremy L Thompson   ceed->work_vectors->is_in_use[i] = true;
91973501bfeSJeremy L Thompson   *vec                             = NULL;
92073501bfeSJeremy L Thompson   CeedCall(CeedVectorReferenceCopy(ceed->work_vectors->vecs[i], vec));
921*b0f67a9cSJeremy L Thompson   // Note: bump ref_count to account for external access
922*b0f67a9cSJeremy L Thompson   CeedCall(CeedObjectReference((CeedObject)ceed));
92373501bfeSJeremy L Thompson   return CEED_ERROR_SUCCESS;
92473501bfeSJeremy L Thompson }
92573501bfeSJeremy L Thompson 
92673501bfeSJeremy L Thompson /**
92773501bfeSJeremy L Thompson   @brief Restore a `CeedVector` for scratch work from a `Ceed` context from @ref CeedGetWorkVector()
92873501bfeSJeremy L Thompson 
92973501bfeSJeremy L Thompson   @param[in]  ceed `Ceed` context
93073501bfeSJeremy L Thompson   @param[out] vec  `CeedVector` to restore
93173501bfeSJeremy L Thompson 
93273501bfeSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
93373501bfeSJeremy L Thompson 
93473501bfeSJeremy L Thompson   @ref Backend
93573501bfeSJeremy L Thompson **/
93673501bfeSJeremy L Thompson int CeedRestoreWorkVector(Ceed ceed, CeedVector *vec) {
937fd326ce8SZach Atkins   if (!ceed->VectorCreate) {
938fd326ce8SZach Atkins     Ceed delegate;
939fd326ce8SZach Atkins 
940fd326ce8SZach Atkins     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Vector"));
941fd326ce8SZach Atkins     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement VectorCreate");
942fd326ce8SZach Atkins     CeedCall(CeedRestoreWorkVector(delegate, vec));
943fd326ce8SZach Atkins     CeedCall(CeedDestroy(&delegate));
944fd326ce8SZach Atkins     return CEED_ERROR_SUCCESS;
945fd326ce8SZach Atkins   }
946fd326ce8SZach Atkins 
94773501bfeSJeremy L Thompson   for (CeedInt i = 0; i < ceed->work_vectors->num_vecs; i++) {
94873501bfeSJeremy L Thompson     if (*vec == ceed->work_vectors->vecs[i]) {
94973501bfeSJeremy L Thompson       CeedCheck(ceed->work_vectors->is_in_use[i], ceed, CEED_ERROR_ACCESS, "Work vector %" CeedSize_FMT " was not checked out but is being returned");
95073501bfeSJeremy L Thompson       CeedCall(CeedVectorDestroy(vec));
95173501bfeSJeremy L Thompson       ceed->work_vectors->is_in_use[i] = false;
952*b0f67a9cSJeremy L Thompson       // Note: reduce ref_count again to prevent a ref-loop
953*b0f67a9cSJeremy L Thompson       CeedObjectDereference((CeedObject)ceed);
95473501bfeSJeremy L Thompson       return CEED_ERROR_SUCCESS;
95573501bfeSJeremy L Thompson     }
95673501bfeSJeremy L Thompson   }
95773501bfeSJeremy L Thompson   // LCOV_EXCL_START
95873501bfeSJeremy L Thompson   return CeedError(ceed, CEED_ERROR_MAJOR, "vec was not checked out via CeedGetWorkVector()");
95973501bfeSJeremy L Thompson   // LCOV_EXCL_STOP
96073501bfeSJeremy L Thompson }
96173501bfeSJeremy L Thompson 
962b13efd58SJeremy L Thompson /**
963b13efd58SJeremy L Thompson   @brief Retrieve list of additional JiT source roots from `Ceed` context.
964b13efd58SJeremy L Thompson 
965b13efd58SJeremy L Thompson   Note: The caller is responsible for restoring `jit_source_roots` with @ref CeedRestoreJitSourceRoots().
966b13efd58SJeremy L Thompson 
967b13efd58SJeremy L Thompson   @param[in]  ceed             `Ceed` context
968b13efd58SJeremy L Thompson   @param[out] num_source_roots Number of JiT source directories
969b13efd58SJeremy L Thompson   @param[out] jit_source_roots Absolute paths to additional JiT source directories
970b13efd58SJeremy L Thompson 
971b13efd58SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
972b13efd58SJeremy L Thompson 
973b13efd58SJeremy L Thompson   @ref Backend
974b13efd58SJeremy L Thompson **/
975b13efd58SJeremy L Thompson int CeedGetJitSourceRoots(Ceed ceed, CeedInt *num_source_roots, const char ***jit_source_roots) {
976b13efd58SJeremy L Thompson   Ceed ceed_parent;
977b13efd58SJeremy L Thompson 
978b13efd58SJeremy L Thompson   CeedCall(CeedGetParent(ceed, &ceed_parent));
979b13efd58SJeremy L Thompson   *num_source_roots = ceed_parent->num_jit_source_roots;
980b13efd58SJeremy L Thompson   *jit_source_roots = (const char **)ceed_parent->jit_source_roots;
981aeb3a72dSJeremy L Thompson   ceed_parent->num_jit_source_roots_readers++;
9829bc66399SJeremy L Thompson   CeedCall(CeedDestroy(&ceed_parent));
983b13efd58SJeremy L Thompson   return CEED_ERROR_SUCCESS;
984b13efd58SJeremy L Thompson }
985b13efd58SJeremy L Thompson 
986b13efd58SJeremy L Thompson /**
9872027fb9dSSirAlienTheGreat   @brief Retrieve list of additional Rust source roots from `Ceed` context.
9882027fb9dSSirAlienTheGreat 
9892027fb9dSSirAlienTheGreat   Note: The caller is responsible for restoring `rust_source_roots` with @ref CeedRestoreRustSourceRoots().
9902027fb9dSSirAlienTheGreat 
9912027fb9dSSirAlienTheGreat   @param[in]  ceed             `Ceed` context
9922027fb9dSSirAlienTheGreat   @param[out] num_source_roots Number of JiT source directories
9932027fb9dSSirAlienTheGreat   @param[out] rust_source_roots Absolute paths to additional Rust source directories
9942027fb9dSSirAlienTheGreat 
9952027fb9dSSirAlienTheGreat   @return An error code: 0 - success, otherwise - failure
9962027fb9dSSirAlienTheGreat 
9972027fb9dSSirAlienTheGreat   @ref Backend
9982027fb9dSSirAlienTheGreat **/
9992027fb9dSSirAlienTheGreat int CeedGetRustSourceRoots(Ceed ceed, CeedInt *num_source_roots, const char ***rust_source_roots) {
10002027fb9dSSirAlienTheGreat   Ceed ceed_parent;
10012027fb9dSSirAlienTheGreat 
10022027fb9dSSirAlienTheGreat   CeedCall(CeedGetParent(ceed, &ceed_parent));
10032027fb9dSSirAlienTheGreat   *num_source_roots  = ceed_parent->num_rust_source_roots;
10042027fb9dSSirAlienTheGreat   *rust_source_roots = (const char **)ceed_parent->rust_source_roots;
10052027fb9dSSirAlienTheGreat   ceed_parent->num_rust_source_roots_readers++;
10062027fb9dSSirAlienTheGreat   CeedCall(CeedDestroy(&ceed_parent));
10072027fb9dSSirAlienTheGreat   return CEED_ERROR_SUCCESS;
10082027fb9dSSirAlienTheGreat }
10092027fb9dSSirAlienTheGreat 
10102027fb9dSSirAlienTheGreat /**
1011b13efd58SJeremy L Thompson   @brief Restore list of additional JiT source roots from with @ref CeedGetJitSourceRoots()
1012b13efd58SJeremy L Thompson 
1013b13efd58SJeremy L Thompson   @param[in]  ceed             `Ceed` context
1014b13efd58SJeremy L Thompson   @param[out] jit_source_roots Absolute paths to additional JiT source directories
1015b13efd58SJeremy L Thompson 
1016b13efd58SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1017b13efd58SJeremy L Thompson 
1018b13efd58SJeremy L Thompson   @ref Backend
1019b13efd58SJeremy L Thompson **/
1020b13efd58SJeremy L Thompson int CeedRestoreJitSourceRoots(Ceed ceed, const char ***jit_source_roots) {
1021aeb3a72dSJeremy L Thompson   Ceed ceed_parent;
1022aeb3a72dSJeremy L Thompson 
1023aeb3a72dSJeremy L Thompson   CeedCall(CeedGetParent(ceed, &ceed_parent));
1024b13efd58SJeremy L Thompson   *jit_source_roots = NULL;
1025aeb3a72dSJeremy L Thompson   ceed_parent->num_jit_source_roots_readers--;
10269bc66399SJeremy L Thompson   CeedCall(CeedDestroy(&ceed_parent));
1027b13efd58SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1028b13efd58SJeremy L Thompson }
1029b13efd58SJeremy L Thompson 
10304753b775SJeremy L Thompson /**
10312027fb9dSSirAlienTheGreat   @brief Restore list of additional Rust source roots from with @ref CeedGetJitSourceRoots()
10322027fb9dSSirAlienTheGreat 
10332027fb9dSSirAlienTheGreat   @param[in]  ceed             `Ceed` context
10342027fb9dSSirAlienTheGreat   @param[out] rust_source_roots Absolute paths to additional Rust source directories
10352027fb9dSSirAlienTheGreat 
10362027fb9dSSirAlienTheGreat   @return An error code: 0 - success, otherwise - failure
10372027fb9dSSirAlienTheGreat 
10382027fb9dSSirAlienTheGreat   @ref Backend
10392027fb9dSSirAlienTheGreat **/
10402027fb9dSSirAlienTheGreat int CeedRestoreRustSourceRoots(Ceed ceed, const char ***rust_source_roots) {
10412027fb9dSSirAlienTheGreat   Ceed ceed_parent;
10422027fb9dSSirAlienTheGreat 
10432027fb9dSSirAlienTheGreat   CeedCall(CeedGetParent(ceed, &ceed_parent));
10442027fb9dSSirAlienTheGreat   *rust_source_roots = NULL;
10452027fb9dSSirAlienTheGreat   ceed_parent->num_rust_source_roots_readers--;
10462027fb9dSSirAlienTheGreat   CeedCall(CeedDestroy(&ceed_parent));
10472027fb9dSSirAlienTheGreat   return CEED_ERROR_SUCCESS;
10482027fb9dSSirAlienTheGreat }
10492027fb9dSSirAlienTheGreat 
10502027fb9dSSirAlienTheGreat /**
10514753b775SJeremy L Thompson   @brief Retrieve list of additional JiT defines from `Ceed` context.
10524753b775SJeremy L Thompson 
10534753b775SJeremy L Thompson   Note: The caller is responsible for restoring `jit_defines` with @ref CeedRestoreJitDefines().
10544753b775SJeremy L Thompson 
10554753b775SJeremy L Thompson   @param[in]  ceed            `Ceed` context
10564753b775SJeremy L Thompson   @param[out] num_jit_defines Number of JiT defines
10574753b775SJeremy L Thompson   @param[out] jit_defines     Strings such as `foo=bar`, used as `-Dfoo=bar` in JiT
10584753b775SJeremy L Thompson 
10594753b775SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
10604753b775SJeremy L Thompson 
10614753b775SJeremy L Thompson   @ref Backend
10624753b775SJeremy L Thompson **/
10632686ebe6SJed Brown int CeedGetJitDefines(Ceed ceed, CeedInt *num_jit_defines, const char ***jit_defines) {
10644753b775SJeremy L Thompson   Ceed ceed_parent;
10654753b775SJeremy L Thompson 
10664753b775SJeremy L Thompson   CeedCall(CeedGetParent(ceed, &ceed_parent));
10672686ebe6SJed Brown   *num_jit_defines = ceed_parent->num_jit_defines;
10684753b775SJeremy L Thompson   *jit_defines     = (const char **)ceed_parent->jit_defines;
1069aeb3a72dSJeremy L Thompson   ceed_parent->num_jit_defines_readers++;
10709bc66399SJeremy L Thompson   CeedCall(CeedDestroy(&ceed_parent));
10714753b775SJeremy L Thompson   return CEED_ERROR_SUCCESS;
10724753b775SJeremy L Thompson }
10734753b775SJeremy L Thompson 
10744753b775SJeremy L Thompson /**
10754753b775SJeremy L Thompson   @brief Restore list of additional JiT defines from with @ref CeedGetJitDefines()
10764753b775SJeremy L Thompson 
10774753b775SJeremy L Thompson   @param[in]  ceed        `Ceed` context
10784753b775SJeremy L Thompson   @param[out] jit_defines String such as `foo=bar`, used as `-Dfoo=bar` in JiT
10794753b775SJeremy L Thompson 
10804753b775SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
10814753b775SJeremy L Thompson 
10824753b775SJeremy L Thompson   @ref Backend
10834753b775SJeremy L Thompson **/
10844753b775SJeremy L Thompson int CeedRestoreJitDefines(Ceed ceed, const char ***jit_defines) {
1085aeb3a72dSJeremy L Thompson   Ceed ceed_parent;
1086aeb3a72dSJeremy L Thompson 
1087aeb3a72dSJeremy L Thompson   CeedCall(CeedGetParent(ceed, &ceed_parent));
10884753b775SJeremy L Thompson   *jit_defines = NULL;
1089aeb3a72dSJeremy L Thompson   ceed_parent->num_jit_defines_readers--;
10909bc66399SJeremy L Thompson   CeedCall(CeedDestroy(&ceed_parent));
10914753b775SJeremy L Thompson   return CEED_ERROR_SUCCESS;
10924753b775SJeremy L Thompson }
10934753b775SJeremy L Thompson 
10947a982d89SJeremy L. Thompson /// @}
10957a982d89SJeremy L. Thompson 
10967a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
10977a982d89SJeremy L. Thompson /// Ceed Public API
10987a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
10997a982d89SJeremy L. Thompson /// @addtogroup CeedUser
11007a982d89SJeremy L. Thompson /// @{
11017a982d89SJeremy L. Thompson 
11027a982d89SJeremy L. Thompson /**
1103ca94c3ddSJeremy L Thompson   @brief Get the list of available resource names for `Ceed` contexts
11044385fb7fSSebastian Grimberg 
1105ca94c3ddSJeremy 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.
110622e44211Sjeremylt 
110792ee7d1cSjeremylt   @param[out] n          Number of available resources
110892ee7d1cSjeremylt   @param[out] resources  List of available resource names
110922e44211Sjeremylt   @param[out] priorities Resource name prioritization values, lower is better
111022e44211Sjeremylt 
111122e44211Sjeremylt   @return An error code: 0 - success, otherwise - failure
111222e44211Sjeremylt 
111322e44211Sjeremylt   @ref User
111422e44211Sjeremylt **/
111522e44211Sjeremylt // LCOV_EXCL_START
11162b730f8bSJeremy L Thompson int CeedRegistryGetList(size_t *n, char ***const resources, CeedInt **priorities) {
1117d0c91ce9Sjeremylt   *n         = 0;
11189ff86846Sjeremylt   *resources = malloc(num_backends * sizeof(**resources));
11196574a04fSJeremy L Thompson   CeedCheck(resources, NULL, CEED_ERROR_MAJOR, "malloc() failure");
11209ff86846Sjeremylt   if (priorities) {
11219ff86846Sjeremylt     *priorities = malloc(num_backends * sizeof(**priorities));
11226574a04fSJeremy L Thompson     CeedCheck(priorities, NULL, CEED_ERROR_MAJOR, "malloc() failure");
11239ff86846Sjeremylt   }
112422e44211Sjeremylt   for (size_t i = 0; i < num_backends; i++) {
1125d0c91ce9Sjeremylt     // Only report compiled backends
1126d0c91ce9Sjeremylt     if (backends[i].priority < CEED_MAX_BACKEND_PRIORITY) {
112722e44211Sjeremylt       *resources[i] = backends[i].prefix;
11289ff86846Sjeremylt       if (priorities) *priorities[i] = backends[i].priority;
1129d0c91ce9Sjeremylt       *n += 1;
1130d0c91ce9Sjeremylt     }
1131d0c91ce9Sjeremylt   }
11326574a04fSJeremy L Thompson   CeedCheck(*n, NULL, CEED_ERROR_MAJOR, "No backends installed");
1133d0c91ce9Sjeremylt   *resources = realloc(*resources, *n * sizeof(**resources));
11346574a04fSJeremy L Thompson   CeedCheck(resources, NULL, CEED_ERROR_MAJOR, "realloc() failure");
1135d0c91ce9Sjeremylt   if (priorities) {
1136d0c91ce9Sjeremylt     *priorities = realloc(*priorities, *n * sizeof(**priorities));
11376574a04fSJeremy L Thompson     CeedCheck(priorities, NULL, CEED_ERROR_MAJOR, "realloc() failure");
113822e44211Sjeremylt   }
113922e44211Sjeremylt   return CEED_ERROR_SUCCESS;
114045f1e315Sjeremylt }
114122e44211Sjeremylt // LCOV_EXCL_STOP
114222e44211Sjeremylt 
114322e44211Sjeremylt /**
1144ca94c3ddSJeremy L Thompson   @brief Initialize a `Ceed` context to use the specified resource.
11454385fb7fSSebastian Grimberg 
1146ca94c3ddSJeremy 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`.
1147b11c1e72Sjeremylt 
1148ea61e9acSJeremy L Thompson   @param[in]  resource Resource to use, e.g., "/cpu/self"
1149ea61e9acSJeremy L Thompson   @param[out] ceed     The library context
1150b11c1e72Sjeremylt 
1151b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1152dfdf5a53Sjeremylt 
11537a982d89SJeremy L. Thompson   @ref User
1154ca94c3ddSJeremy L Thompson 
1155ca94c3ddSJeremy L Thompson   @sa CeedRegister() CeedDestroy()
1156b11c1e72Sjeremylt **/
1157d7b241e6Sjeremylt int CeedInit(const char *resource, Ceed *ceed) {
11582b730f8bSJeremy L Thompson   size_t match_len = 0, match_index = UINT_MAX, match_priority = CEED_MAX_BACKEND_PRIORITY, priority;
1159d7b241e6Sjeremylt 
1160fe2413ffSjeremylt   // Find matching backend
11616574a04fSJeremy L Thompson   CeedCheck(resource, NULL, CEED_ERROR_MAJOR, "No resource provided");
11622b730f8bSJeremy L Thompson   CeedCall(CeedRegisterAll());
116313873f79Sjeremylt 
116422e44211Sjeremylt   // Check for help request
116522e44211Sjeremylt   const char *help_prefix = "help";
11662b730f8bSJeremy L Thompson   size_t      match_help  = 0;
11672b730f8bSJeremy L Thompson   while (match_help < 4 && resource[match_help] == help_prefix[match_help]) match_help++;
116822e44211Sjeremylt   if (match_help == 4) {
11692b730f8bSJeremy L Thompson     fprintf(stderr, "libCEED version: %d.%d%d%s\n", CEED_VERSION_MAJOR, CEED_VERSION_MINOR, CEED_VERSION_PATCH,
117022e44211Sjeremylt             CEED_VERSION_RELEASE ? "" : "+development");
117192ee7d1cSjeremylt     fprintf(stderr, "Available backend resources:\n");
117222e44211Sjeremylt     for (size_t i = 0; i < num_backends; i++) {
1173d0c91ce9Sjeremylt       // Only report compiled backends
11742b730f8bSJeremy L Thompson       if (backends[i].priority < CEED_MAX_BACKEND_PRIORITY) fprintf(stderr, "  %s\n", backends[i].prefix);
117522e44211Sjeremylt     }
117622e44211Sjeremylt     fflush(stderr);
117722e44211Sjeremylt     match_help = 5;  // Delineating character expected
117822e44211Sjeremylt   } else {
117922e44211Sjeremylt     match_help = 0;
118022e44211Sjeremylt   }
118122e44211Sjeremylt 
1182ea61e9acSJeremy L Thompson   // Find best match, computed as number of matching characters from requested resource stem
11832b730f8bSJeremy L Thompson   size_t stem_length = 0;
11842b730f8bSJeremy L Thompson   while (resource[stem_length + match_help] && resource[stem_length + match_help] != ':') stem_length++;
1185d7b241e6Sjeremylt   for (size_t i = 0; i < num_backends; i++) {
11862b730f8bSJeremy L Thompson     size_t      n      = 0;
1187d7b241e6Sjeremylt     const char *prefix = backends[i].prefix;
11882b730f8bSJeremy L Thompson     while (prefix[n] && prefix[n] == resource[n + match_help]) n++;
1189d7b241e6Sjeremylt     priority = backends[i].priority;
1190d1d35e2fSjeremylt     if (n > match_len || (n == match_len && match_priority > priority)) {
1191d1d35e2fSjeremylt       match_len      = n;
1192d1d35e2fSjeremylt       match_priority = priority;
1193f7e22acaSJeremy L Thompson       match_index    = i;
1194d7b241e6Sjeremylt     }
1195d7b241e6Sjeremylt   }
11969c9a0587SLeila Ghaffari   // Using Levenshtein distance to find closest match
11979c9a0587SLeila Ghaffari   if (match_len <= 1 || match_len != stem_length) {
1198203015caSLeila Ghaffari     // LCOV_EXCL_START
11999c9a0587SLeila Ghaffari     size_t lev_dis   = UINT_MAX;
1200f7e22acaSJeremy L Thompson     size_t lev_index = UINT_MAX, lev_priority = CEED_MAX_BACKEND_PRIORITY;
12019c9a0587SLeila Ghaffari     for (size_t i = 0; i < num_backends; i++) {
12029c9a0587SLeila Ghaffari       const char *prefix        = backends[i].prefix;
12039c9a0587SLeila Ghaffari       size_t      prefix_length = strlen(backends[i].prefix);
12049c9a0587SLeila Ghaffari       size_t      min_len       = (prefix_length < stem_length) ? prefix_length : stem_length;
1205092904ddSLeila Ghaffari       size_t      column[min_len + 1];
1206092904ddSLeila Ghaffari       for (size_t j = 0; j <= min_len; j++) column[j] = j;
12079c9a0587SLeila Ghaffari       for (size_t j = 1; j <= min_len; j++) {
12089c9a0587SLeila Ghaffari         column[0] = j;
12099c9a0587SLeila Ghaffari         for (size_t k = 1, last_diag = j - 1; k <= min_len; k++) {
1210092904ddSLeila Ghaffari           size_t old_diag = column[k];
12119c9a0587SLeila Ghaffari           size_t min_1    = (column[k] < column[k - 1]) ? column[k] + 1 : column[k - 1] + 1;
12129c9a0587SLeila Ghaffari           size_t min_2    = last_diag + (resource[k - 1] == prefix[j - 1] ? 0 : 1);
12139c9a0587SLeila Ghaffari           column[k]       = (min_1 < min_2) ? min_1 : min_2;
12149c9a0587SLeila Ghaffari           last_diag       = old_diag;
12159c9a0587SLeila Ghaffari         }
12169c9a0587SLeila Ghaffari       }
12179c9a0587SLeila Ghaffari       size_t n = column[min_len];
12189c9a0587SLeila Ghaffari       priority = backends[i].priority;
12192b730f8bSJeremy L Thompson       if (n < lev_dis || (n == lev_dis && lev_priority > priority)) {
12209c9a0587SLeila Ghaffari         lev_dis      = n;
12219c9a0587SLeila Ghaffari         lev_priority = priority;
1222f7e22acaSJeremy L Thompson         lev_index    = i;
12239c9a0587SLeila Ghaffari       }
12249c9a0587SLeila Ghaffari     }
1225f7e22acaSJeremy L Thompson     const char *prefix_lev = backends[lev_index].prefix;
12262b730f8bSJeremy L Thompson     size_t      lev_length = 0;
12272b730f8bSJeremy L Thompson     while (prefix_lev[lev_length] && prefix_lev[lev_length] != '\0') lev_length++;
12289c9a0587SLeila Ghaffari     size_t m = (lev_length < stem_length) ? lev_length : stem_length;
12296574a04fSJeremy L Thompson     if (lev_dis + 1 >= m) return CeedError(NULL, CEED_ERROR_MAJOR, "No suitable backend: %s", resource);
12306574a04fSJeremy L Thompson     else return CeedError(NULL, CEED_ERROR_MAJOR, "No suitable backend: %s\nClosest match: %s", resource, backends[lev_index].prefix);
1231203015caSLeila Ghaffari     // LCOV_EXCL_STOP
12329c9a0587SLeila Ghaffari   }
1233fe2413ffSjeremylt 
1234fe2413ffSjeremylt   // Setup Ceed
12352b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, ceed));
1236*b0f67a9cSJeremy L Thompson   CeedCall(CeedObjectCreate(NULL, CeedView_Object, &(*ceed)->obj));
12372b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, &(*ceed)->jit_source_roots));
12382027fb9dSSirAlienTheGreat   CeedCall(CeedCalloc(1, &(*ceed)->rust_source_roots));
1239bc81ce41Sjeremylt   const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER");
12402b730f8bSJeremy L Thompson   if (!ceed_error_handler) ceed_error_handler = "abort";
12412b730f8bSJeremy L Thompson   if (!strcmp(ceed_error_handler, "exit")) (*ceed)->Error = CeedErrorExit;
12422b730f8bSJeremy L Thompson   else if (!strcmp(ceed_error_handler, "store")) (*ceed)->Error = CeedErrorStore;
12432b730f8bSJeremy L Thompson   else (*ceed)->Error = CeedErrorAbort;
1244d1d35e2fSjeremylt   memcpy((*ceed)->err_msg, "No error message stored", 24);
1245d7b241e6Sjeremylt   (*ceed)->data = NULL;
1246fe2413ffSjeremylt 
1247fe2413ffSjeremylt   // Set lookup table
1248d1d35e2fSjeremylt   FOffset f_offsets[] = {
12496e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, Error),
12505ae360d4SJeremy L Thompson       CEED_FTABLE_ENTRY(Ceed, SetStream),
12516e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, GetPreferredMemType),
12526e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, Destroy),
1253f8902d9eSjeremylt       CEED_FTABLE_ENTRY(Ceed, VectorCreate),
12546e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreate),
12553ac8f562SJeremy L Thompson       CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateAtPoints),
12566e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked),
12576e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1),
12586e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, BasisCreateH1),
125950c301a5SRezgar Shakeri       CEED_FTABLE_ENTRY(Ceed, BasisCreateHdiv),
1260c4e3f59bSSebastian Grimberg       CEED_FTABLE_ENTRY(Ceed, BasisCreateHcurl),
12616e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, TensorContractCreate),
12626e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, QFunctionCreate),
1263777ff853SJeremy L Thompson       CEED_FTABLE_ENTRY(Ceed, QFunctionContextCreate),
12646e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, OperatorCreate),
126548acf710SJeremy L Thompson       CEED_FTABLE_ENTRY(Ceed, OperatorCreateAtPoints),
12666e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate),
12679c774eddSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, HasValidArray),
12689c774eddSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, HasBorrowedArrayOfType),
12690b8f3c4eSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, CopyStrided),
12706e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, SetArray),
12716a6c615bSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, TakeArray),
12726e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, SetValue),
12730b8f3c4eSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, SetValueStrided),
1274f48ed27dSnbeams       CEED_FTABLE_ENTRY(CeedVector, SyncArray),
12756e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, GetArray),
12766e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, GetArrayRead),
12779c774eddSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, GetArrayWrite),
12786e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, RestoreArray),
12796e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead),
1280547d9b97Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, Norm),
1281e0dd3b27Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, Scale),
12820f7fd0f8Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, AXPY),
12835fb68f37SKaren (Ren) Stengel       CEED_FTABLE_ENTRY(CeedVector, AXPBY),
12840f7fd0f8Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, PointwiseMult),
1285d99fa3c5SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, Reciprocal),
12866e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, Destroy),
12876e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedElemRestriction, Apply),
1288f30b1135SSebastian Grimberg       CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyUnsigned),
12897c1dbaffSSebastian Grimberg       CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyUnoriented),
129005fa913cSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyAtPointsInElement),
12916e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock),
1292bd33150aSjeremylt       CEED_FTABLE_ENTRY(CeedElemRestriction, GetOffsets),
129377d1c127SSebastian Grimberg       CEED_FTABLE_ENTRY(CeedElemRestriction, GetOrientations),
129477d1c127SSebastian Grimberg       CEED_FTABLE_ENTRY(CeedElemRestriction, GetCurlOrientations),
129519605835SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedElemRestriction, GetAtPointsElementOffset),
12966e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy),
12976e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedBasis, Apply),
1298db2becc9SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedBasis, ApplyAdd),
1299c8c3fa7dSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedBasis, ApplyAtPoints),
1300db2becc9SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedBasis, ApplyAddAtPoints),
13016e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedBasis, Destroy),
13026e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedTensorContract, Apply),
13036e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedTensorContract, Destroy),
13046e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedQFunction, Apply),
13058c84ac63Sjeremylt       CEED_FTABLE_ENTRY(CeedQFunction, SetCUDAUserFunction),
13068c84ac63Sjeremylt       CEED_FTABLE_ENTRY(CeedQFunction, SetHIPUserFunction),
13076e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedQFunction, Destroy),
13089c774eddSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, HasValidData),
13099c774eddSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, HasBorrowedDataOfType),
1310777ff853SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, SetData),
1311891038deSjeremylt       CEED_FTABLE_ENTRY(CeedQFunctionContext, TakeData),
1312777ff853SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, GetData),
131328bfd0b7SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, GetDataRead),
1314777ff853SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, RestoreData),
131528bfd0b7SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, RestoreDataRead),
13162e64a2b9SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, DataDestroy),
1317777ff853SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, Destroy),
131880ac2e43SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunction),
131970a7ffb3SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunctionUpdate),
132080ac2e43SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleDiagonal),
13219e9210b8SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddDiagonal),
132280ac2e43SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssemblePointBlockDiagonal),
13239e9210b8SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddPointBlockDiagonal),
1324e2f04181SAndrew T. Barker       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleSymbolic),
1325e2f04181SAndrew T. Barker       CEED_FTABLE_ENTRY(CeedOperator, LinearAssemble),
1326cefa2673SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleSingle),
1327713f43c3Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, CreateFDMElementInverse),
13286e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, Apply),
1329250756a7Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, ApplyComposite),
1330cae8b89aSjeremylt       CEED_FTABLE_ENTRY(CeedOperator, ApplyAdd),
1331250756a7Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, ApplyAddComposite),
13326e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian),
13336e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, Destroy),
13346e79d475Sjeremylt       {NULL, 0}  // End of lookup table - used in SetBackendFunction loop
13351dfeef1dSjeremylt   };
1336fe2413ffSjeremylt 
13372b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(sizeof(f_offsets), &(*ceed)->f_offsets));
1338d1d35e2fSjeremylt   memcpy((*ceed)->f_offsets, f_offsets, sizeof(f_offsets));
1339fe2413ffSjeremylt 
134060f9e2d6SJeremy L Thompson   // Record env variables CEED_DEBUG or DBG
13411c66c397SJeremy L Thompson   (*ceed)->is_debug = getenv("CEED_DEBUG") || getenv("DEBUG") || getenv("DBG");
134260f9e2d6SJeremy L Thompson 
134322e44211Sjeremylt   // Copy resource prefix, if backend setup successful
13442b730f8bSJeremy L Thompson   CeedCall(CeedStringAllocCopy(backends[match_index].prefix, (char **)&(*ceed)->resource));
1345ee5a26f2SJeremy L Thompson 
1346ee5a26f2SJeremy L Thompson   // Set default JiT source root
1347ea61e9acSJeremy L Thompson   // Note: there will always be the default root for every Ceed but all additional paths are added to the top-most parent
13482b730f8bSJeremy L Thompson   CeedCall(CeedAddJitSourceRoot(*ceed, (char *)CeedJitSourceRootDefault));
1349ee5a26f2SJeremy L Thompson 
13502027fb9dSSirAlienTheGreat   // By default, make cuda compile without clang, use nvrtc instead
13512027fb9dSSirAlienTheGreat   // Note that this is overridden if a rust file is included (rust requires clang)
13522027fb9dSSirAlienTheGreat   const char *env = getenv("GPU_CLANG");
13532027fb9dSSirAlienTheGreat 
13542027fb9dSSirAlienTheGreat   if (env && strcmp(env, "1") == 0) {
13552027fb9dSSirAlienTheGreat     (*ceed)->cuda_compile_with_clang = true;
13562027fb9dSSirAlienTheGreat   } else {
13572027fb9dSSirAlienTheGreat     (*ceed)->cuda_compile_with_clang = false;
13582027fb9dSSirAlienTheGreat   }
13592027fb9dSSirAlienTheGreat 
1360d04bbc78SJeremy L Thompson   // Backend specific setup
13612b730f8bSJeremy L Thompson   CeedCall(backends[match_index].init(&resource[match_help], *ceed));
1362e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1363d7b241e6Sjeremylt }
1364d7b241e6Sjeremylt 
1365d7b241e6Sjeremylt /**
1366ca94c3ddSJeremy L Thompson   @brief Set the GPU stream for a `Ceed` context
13675ae360d4SJeremy L Thompson 
1368ca94c3ddSJeremy L Thompson   @param[in,out] ceed   `Ceed` context to set the stream
13695ae360d4SJeremy L Thompson   @param[in]     handle Handle to GPU stream
13705ae360d4SJeremy L Thompson 
13715ae360d4SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
13725ae360d4SJeremy L Thompson 
13735ae360d4SJeremy L Thompson   @ref User
13745ae360d4SJeremy L Thompson **/
13755ae360d4SJeremy L Thompson int CeedSetStream(Ceed ceed, void *handle) {
1376ca94c3ddSJeremy L Thompson   CeedCheck(handle, ceed, CEED_ERROR_INCOMPATIBLE, "Stream handle must be non-NULL");
13779ffb25e0SJames Wright   if (ceed->SetStream) {
13785ae360d4SJeremy L Thompson     CeedCall(ceed->SetStream(ceed, handle));
13799ffb25e0SJames Wright   } else {
13809ffb25e0SJames Wright     Ceed delegate;
13819ffb25e0SJames Wright     CeedCall(CeedGetDelegate(ceed, &delegate));
13825ae360d4SJeremy L Thompson 
138328ce3d2aSJeremy L Thompson     if (delegate) CeedCall(CeedSetStream(delegate, handle));
138428ce3d2aSJeremy L Thompson     else return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support setting stream");
13859bc66399SJeremy L Thompson     CeedCall(CeedDestroy(&delegate));
13869ffb25e0SJames Wright   }
13875ae360d4SJeremy L Thompson   return CEED_ERROR_SUCCESS;
13885ae360d4SJeremy L Thompson }
13895ae360d4SJeremy L Thompson 
13905ae360d4SJeremy L Thompson /**
1391ca94c3ddSJeremy L Thompson   @brief Copy the pointer to a `Ceed` context.
13924385fb7fSSebastian Grimberg 
1393ca94c3ddSJeremy L Thompson   Both pointers should be destroyed with @ref CeedDestroy().
1394512bb800SJeremy L Thompson 
1395ca94c3ddSJeremy 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.
1396ca94c3ddSJeremy L Thompson         This `Ceed` context will be destroyed if `*ceed_copy` is the only reference to this `Ceed` context.
13979560d06aSjeremylt 
1398ca94c3ddSJeremy L Thompson   @param[in]     ceed      `Ceed` context to copy reference to
1399ea61e9acSJeremy L Thompson   @param[in,out] ceed_copy Variable to store copied reference
14009560d06aSjeremylt 
14019560d06aSjeremylt   @return An error code: 0 - success, otherwise - failure
14029560d06aSjeremylt 
14039560d06aSjeremylt   @ref User
14049560d06aSjeremylt **/
14059560d06aSjeremylt int CeedReferenceCopy(Ceed ceed, Ceed *ceed_copy) {
14062b730f8bSJeremy L Thompson   CeedCall(CeedReference(ceed));
14072b730f8bSJeremy L Thompson   CeedCall(CeedDestroy(ceed_copy));
14089560d06aSjeremylt   *ceed_copy = ceed;
14099560d06aSjeremylt   return CEED_ERROR_SUCCESS;
14109560d06aSjeremylt }
14119560d06aSjeremylt 
14129560d06aSjeremylt /**
1413ca94c3ddSJeremy L Thompson   @brief Get the full resource name for a `Ceed` context
14142f86a920SJeremy L Thompson 
1415ca94c3ddSJeremy L Thompson   @param[in]  ceed     `Ceed` context to get resource name of
14167a982d89SJeremy L. Thompson   @param[out] resource Variable to store resource name
14172f86a920SJeremy L Thompson 
14182f86a920SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
14192f86a920SJeremy L Thompson 
14207a982d89SJeremy L. Thompson   @ref User
14215107b09fSJeremy L Thompson **/
14227a982d89SJeremy L. Thompson int CeedGetResource(Ceed ceed, const char **resource) {
14237a982d89SJeremy L. Thompson   *resource = (const char *)ceed->resource;
1424e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
14255107b09fSJeremy L Thompson }
14265107b09fSJeremy L Thompson 
14275107b09fSJeremy L Thompson /**
1428ca94c3ddSJeremy L Thompson   @brief Return `Ceed` context preferred memory type
1429c907536fSjeremylt 
1430ca94c3ddSJeremy L Thompson   @param[in]  ceed     `Ceed` context to get preferred memory type of
1431d1d35e2fSjeremylt   @param[out] mem_type Address to save preferred memory type to
1432c907536fSjeremylt 
1433c907536fSjeremylt   @return An error code: 0 - success, otherwise - failure
1434c907536fSjeremylt 
14357a982d89SJeremy L. Thompson   @ref User
1436c907536fSjeremylt **/
1437d1d35e2fSjeremylt int CeedGetPreferredMemType(Ceed ceed, CeedMemType *mem_type) {
1438c907536fSjeremylt   if (ceed->GetPreferredMemType) {
14392b730f8bSJeremy L Thompson     CeedCall(ceed->GetPreferredMemType(mem_type));
1440c907536fSjeremylt   } else {
1441c263cd57Sjeremylt     Ceed delegate;
14422b730f8bSJeremy L Thompson     CeedCall(CeedGetDelegate(ceed, &delegate));
1443c263cd57Sjeremylt 
1444c263cd57Sjeremylt     if (delegate) {
14452b730f8bSJeremy L Thompson       CeedCall(CeedGetPreferredMemType(delegate, mem_type));
1446c263cd57Sjeremylt     } else {
1447d1d35e2fSjeremylt       *mem_type = CEED_MEM_HOST;
1448c907536fSjeremylt     }
14499bc66399SJeremy L Thompson     CeedCall(CeedDestroy(&delegate));
1450c263cd57Sjeremylt   }
1451e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1452c907536fSjeremylt }
1453c907536fSjeremylt 
1454c907536fSjeremylt /**
1455ca94c3ddSJeremy L Thompson   @brief Get deterministic status of `Ceed` context
14569525855cSJeremy L Thompson 
1457ca94c3ddSJeremy L Thompson   @param[in]  ceed             `Ceed` context
1458d1d35e2fSjeremylt   @param[out] is_deterministic Variable to store deterministic status
14599525855cSJeremy L Thompson 
14609525855cSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
14619525855cSJeremy L Thompson 
14629525855cSJeremy L Thompson   @ref User
14639525855cSJeremy L Thompson **/
1464d1d35e2fSjeremylt int CeedIsDeterministic(Ceed ceed, bool *is_deterministic) {
1465d1d35e2fSjeremylt   *is_deterministic = ceed->is_deterministic;
1466e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
14679525855cSJeremy L Thompson }
14689525855cSJeremy L Thompson 
14699525855cSJeremy L Thompson /**
1470ca94c3ddSJeremy L Thompson   @brief Set additional JiT source root for `Ceed` context
1471ee5a26f2SJeremy L Thompson 
1472ca94c3ddSJeremy L Thompson   @param[in,out] ceed            `Ceed` context
1473ee5a26f2SJeremy L Thompson   @param[in]     jit_source_root Absolute path to additional JiT source directory
1474ee5a26f2SJeremy L Thompson 
1475ee5a26f2SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1476ee5a26f2SJeremy L Thompson 
1477ee5a26f2SJeremy L Thompson   @ref User
1478ee5a26f2SJeremy L Thompson **/
1479ee5a26f2SJeremy L Thompson int CeedAddJitSourceRoot(Ceed ceed, const char *jit_source_root) {
14806155f12fSJeremy L Thompson   Ceed ceed_parent;
1481ee5a26f2SJeremy L Thompson 
14822b730f8bSJeremy L Thompson   CeedCall(CeedGetParent(ceed, &ceed_parent));
1483830fc37bSJeremy L Thompson   CeedCheck(!ceed_parent->num_jit_source_roots_readers, ceed, CEED_ERROR_ACCESS, "Cannot add JiT source root, read access has not been restored");
14846155f12fSJeremy L Thompson 
14856155f12fSJeremy L Thompson   CeedInt index       = ceed_parent->num_jit_source_roots;
1486ee5a26f2SJeremy L Thompson   size_t  path_length = strlen(jit_source_root);
14871c66c397SJeremy L Thompson 
14884753b775SJeremy L Thompson   if (ceed_parent->num_jit_source_roots == ceed_parent->max_jit_source_roots) {
14894753b775SJeremy L Thompson     if (ceed_parent->max_jit_source_roots == 0) ceed_parent->max_jit_source_roots = 1;
14904753b775SJeremy L Thompson     ceed_parent->max_jit_source_roots *= 2;
14914753b775SJeremy L Thompson     CeedCall(CeedRealloc(ceed_parent->max_jit_source_roots, &ceed_parent->jit_source_roots));
14924753b775SJeremy L Thompson   }
14932b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(path_length + 1, &ceed_parent->jit_source_roots[index]));
1494d602d780SJeremy L Thompson   memcpy(ceed_parent->jit_source_roots[index], jit_source_root, path_length);
14956155f12fSJeremy L Thompson   ceed_parent->num_jit_source_roots++;
14969bc66399SJeremy L Thompson   CeedCall(CeedDestroy(&ceed_parent));
1497ee5a26f2SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1498ee5a26f2SJeremy L Thompson }
1499ee5a26f2SJeremy L Thompson 
1500ee5a26f2SJeremy L Thompson /**
15012027fb9dSSirAlienTheGreat   @brief Set additional Rust source root for `Ceed` context for use in QFunction
15022027fb9dSSirAlienTheGreat 
15032027fb9dSSirAlienTheGreat   @param[in,out] ceed            `Ceed` context
15042027fb9dSSirAlienTheGreat   @param[in]     rust_source_root Absolute path to additional Rust source directory
15052027fb9dSSirAlienTheGreat 
15062027fb9dSSirAlienTheGreat   @return An error code: 0 - success, otherwise - failure
15072027fb9dSSirAlienTheGreat 
15082027fb9dSSirAlienTheGreat   @ref User
15092027fb9dSSirAlienTheGreat **/
15102027fb9dSSirAlienTheGreat int CeedAddRustSourceRoot(Ceed ceed, const char *rust_source_root) {
15112027fb9dSSirAlienTheGreat   Ceed ceed_parent;
15122027fb9dSSirAlienTheGreat 
15132027fb9dSSirAlienTheGreat   CeedCall(CeedGetParent(ceed, &ceed_parent));
15142027fb9dSSirAlienTheGreat   CeedCheck(!ceed_parent->num_rust_source_roots_readers, ceed, CEED_ERROR_ACCESS, "Cannot add Rust source root, read access has not been restored");
15152027fb9dSSirAlienTheGreat 
15162027fb9dSSirAlienTheGreat   CeedInt index       = ceed_parent->num_rust_source_roots;
15172027fb9dSSirAlienTheGreat   size_t  path_length = strlen(rust_source_root);
15182027fb9dSSirAlienTheGreat 
15192027fb9dSSirAlienTheGreat   if (ceed_parent->num_rust_source_roots == ceed_parent->max_rust_source_roots) {
15202027fb9dSSirAlienTheGreat     if (ceed_parent->max_rust_source_roots == 0) ceed_parent->max_rust_source_roots = 1;
15212027fb9dSSirAlienTheGreat     ceed_parent->max_rust_source_roots *= 2;
15222027fb9dSSirAlienTheGreat     CeedCall(CeedRealloc(ceed_parent->max_rust_source_roots, &ceed_parent->rust_source_roots));
15232027fb9dSSirAlienTheGreat   }
15242027fb9dSSirAlienTheGreat   CeedCall(CeedCalloc(path_length + 1, &ceed_parent->rust_source_roots[index]));
15252027fb9dSSirAlienTheGreat   memcpy(ceed_parent->rust_source_roots[index], rust_source_root, path_length);
15262027fb9dSSirAlienTheGreat   ceed_parent->num_rust_source_roots++;
15272027fb9dSSirAlienTheGreat   ceed_parent->cuda_compile_with_clang = true;
15282027fb9dSSirAlienTheGreat   ceed->cuda_compile_with_clang        = true;
15292027fb9dSSirAlienTheGreat   CeedCall(CeedDestroy(&ceed_parent));
15302027fb9dSSirAlienTheGreat   return CEED_ERROR_SUCCESS;
15312027fb9dSSirAlienTheGreat }
15322027fb9dSSirAlienTheGreat 
15332027fb9dSSirAlienTheGreat /**
15344753b775SJeremy L Thompson   @brief Set additional JiT compiler define for `Ceed` context
15354753b775SJeremy L Thompson 
15364753b775SJeremy L Thompson   @param[in,out] ceed       `Ceed` context
15374753b775SJeremy L Thompson   @param[in]     jit_define String such as `foo=bar`, used as `-Dfoo=bar` in JiT
15384753b775SJeremy L Thompson 
15394753b775SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
15404753b775SJeremy L Thompson 
15414753b775SJeremy L Thompson   @ref User
15424753b775SJeremy L Thompson **/
15434753b775SJeremy L Thompson int CeedAddJitDefine(Ceed ceed, const char *jit_define) {
15444753b775SJeremy L Thompson   Ceed ceed_parent;
15454753b775SJeremy L Thompson 
15464753b775SJeremy L Thompson   CeedCall(CeedGetParent(ceed, &ceed_parent));
1547830fc37bSJeremy L Thompson   CeedCheck(!ceed_parent->num_jit_defines_readers, ceed, CEED_ERROR_ACCESS, "Cannot add JiT define, read access has not been restored");
15484753b775SJeremy L Thompson 
15494753b775SJeremy L Thompson   CeedInt index         = ceed_parent->num_jit_defines;
15504753b775SJeremy L Thompson   size_t  define_length = strlen(jit_define);
15514753b775SJeremy L Thompson 
15524753b775SJeremy L Thompson   if (ceed_parent->num_jit_defines == ceed_parent->max_jit_defines) {
15534753b775SJeremy L Thompson     if (ceed_parent->max_jit_defines == 0) ceed_parent->max_jit_defines = 1;
15544753b775SJeremy L Thompson     ceed_parent->max_jit_defines *= 2;
15554753b775SJeremy L Thompson     CeedCall(CeedRealloc(ceed_parent->max_jit_defines, &ceed_parent->jit_defines));
15564753b775SJeremy L Thompson   }
15574753b775SJeremy L Thompson   CeedCall(CeedCalloc(define_length + 1, &ceed_parent->jit_defines[index]));
15584753b775SJeremy L Thompson   memcpy(ceed_parent->jit_defines[index], jit_define, define_length);
15594753b775SJeremy L Thompson   ceed_parent->num_jit_defines++;
15609bc66399SJeremy L Thompson   CeedCall(CeedDestroy(&ceed_parent));
15614753b775SJeremy L Thompson   return CEED_ERROR_SUCCESS;
15624753b775SJeremy L Thompson }
15634753b775SJeremy L Thompson 
15644753b775SJeremy L Thompson /**
15654c789ea2SJeremy L Thompson   @brief Set the number of tabs to indent for @ref CeedView() output
15664c789ea2SJeremy L Thompson 
15674c789ea2SJeremy L Thompson   @param[in] ceed     `Ceed` to set the number of view tabs
15684c789ea2SJeremy L Thompson   @param[in] num_tabs Number of view tabs to set
15694c789ea2SJeremy L Thompson 
15704c789ea2SJeremy L Thompson   @return Error code: 0 - success, otherwise - failure
15714c789ea2SJeremy L Thompson 
15724c789ea2SJeremy L Thompson   @ref User
15734c789ea2SJeremy L Thompson **/
15744c789ea2SJeremy L Thompson int CeedSetNumViewTabs(Ceed ceed, CeedInt num_tabs) {
15754c789ea2SJeremy L Thompson   CeedCheck(num_tabs >= 0, ceed, CEED_ERROR_MINOR, "Number of view tabs must be non-negative");
15764c789ea2SJeremy L Thompson   ceed->num_tabs = num_tabs;
15774c789ea2SJeremy L Thompson   return CEED_ERROR_SUCCESS;
15784c789ea2SJeremy L Thompson }
15794c789ea2SJeremy L Thompson 
15804c789ea2SJeremy L Thompson /**
1581690992b2SZach Atkins   @brief Get the number of tabs to indent for @ref CeedView() output
1582690992b2SZach Atkins 
1583690992b2SZach Atkins   @param[in]  ceed     `Ceed` to get the number of view tabs
1584690992b2SZach Atkins   @param[out] num_tabs Number of view tabs
1585690992b2SZach Atkins 
1586690992b2SZach Atkins   @return Error code: 0 - success, otherwise - failure
1587690992b2SZach Atkins 
1588690992b2SZach Atkins   @ref User
1589690992b2SZach Atkins **/
1590690992b2SZach Atkins int CeedGetNumViewTabs(Ceed ceed, CeedInt *num_tabs) {
1591690992b2SZach Atkins   *num_tabs = ceed->num_tabs;
1592690992b2SZach Atkins   return CEED_ERROR_SUCCESS;
1593690992b2SZach Atkins }
1594690992b2SZach Atkins 
1595690992b2SZach Atkins /**
1596ca94c3ddSJeremy L Thompson   @brief View a `Ceed`
15970a0da059Sjeremylt 
1598ca94c3ddSJeremy L Thompson   @param[in] ceed   `Ceed` to view
15990a0da059Sjeremylt   @param[in] stream Filestream to write to
16000a0da059Sjeremylt 
16010a0da059Sjeremylt   @return An error code: 0 - success, otherwise - failure
16020a0da059Sjeremylt 
16030a0da059Sjeremylt   @ref User
16040a0da059Sjeremylt **/
16050a0da059Sjeremylt int CeedView(Ceed ceed, FILE *stream) {
16064c789ea2SJeremy L Thompson   char       *tabs = NULL;
1607d1d35e2fSjeremylt   CeedMemType mem_type;
16080a0da059Sjeremylt 
16094c789ea2SJeremy L Thompson   {
16104c789ea2SJeremy L Thompson     CeedInt num_tabs = 0;
16114c789ea2SJeremy L Thompson 
16124c789ea2SJeremy L Thompson     CeedCall(CeedGetNumViewTabs(ceed, &num_tabs));
16134c789ea2SJeremy L Thompson     CeedCall(CeedCalloc(CEED_TAB_WIDTH * num_tabs + 1, &tabs));
16144c789ea2SJeremy L Thompson     for (CeedInt i = 0; i < CEED_TAB_WIDTH * num_tabs; i++) tabs[i] = ' ';
16154c789ea2SJeremy L Thompson   }
16164c789ea2SJeremy L Thompson 
16172b730f8bSJeremy L Thompson   CeedCall(CeedGetPreferredMemType(ceed, &mem_type));
16180a0da059Sjeremylt 
16192b730f8bSJeremy L Thompson   fprintf(stream,
16204c789ea2SJeremy L Thompson           "%sCeed\n"
16214c789ea2SJeremy L Thompson           "%s  Ceed Resource: %s\n"
16224c789ea2SJeremy L Thompson           "%s  Preferred MemType: %s\n",
16234c789ea2SJeremy L Thompson           tabs, tabs, ceed->resource, tabs, CeedMemTypes[mem_type]);
16244c789ea2SJeremy L Thompson   CeedCall(CeedFree(&tabs));
1625e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
16260a0da059Sjeremylt }
16270a0da059Sjeremylt 
16280a0da059Sjeremylt /**
1629ca94c3ddSJeremy L Thompson   @brief Destroy a `Ceed`
1630d7b241e6Sjeremylt 
1631ca94c3ddSJeremy L Thompson   @param[in,out] ceed Address of `Ceed` context to destroy
1632b11c1e72Sjeremylt 
1633b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1634dfdf5a53Sjeremylt 
16357a982d89SJeremy L. Thompson   @ref User
1636b11c1e72Sjeremylt **/
1637d7b241e6Sjeremylt int CeedDestroy(Ceed *ceed) {
1638*b0f67a9cSJeremy L Thompson   if (!*ceed || CeedObjectDereference((CeedObject)*ceed) > 0) {
1639ad6481ceSJeremy L Thompson     *ceed = NULL;
1640ad6481ceSJeremy L Thompson     return CEED_ERROR_SUCCESS;
1641ad6481ceSJeremy L Thompson   }
1642aeb3a72dSJeremy L Thompson 
1643aeb3a72dSJeremy L Thompson   CeedCheck(!(*ceed)->num_jit_source_roots_readers, *ceed, CEED_ERROR_ACCESS,
1644aeb3a72dSJeremy L Thompson             "Cannot destroy ceed context, read access for JiT source roots has been granted");
1645aeb3a72dSJeremy L Thompson   CeedCheck(!(*ceed)->num_jit_defines_readers, *ceed, CEED_ERROR_ACCESS, "Cannot add JiT source root, read access for JiT defines has been granted");
1646aeb3a72dSJeremy L Thompson 
16472b730f8bSJeremy L Thompson   if ((*ceed)->delegate) CeedCall(CeedDestroy(&(*ceed)->delegate));
16480ace9bf2Sjeremylt 
1649d1d35e2fSjeremylt   if ((*ceed)->obj_delegate_count > 0) {
165092ae7e47SJeremy L Thompson     for (CeedInt i = 0; i < (*ceed)->obj_delegate_count; i++) {
16512b730f8bSJeremy L Thompson       CeedCall(CeedDestroy(&((*ceed)->obj_delegates[i].delegate)));
16522b730f8bSJeremy L Thompson       CeedCall(CeedFree(&(*ceed)->obj_delegates[i].obj_name));
1653aefd8378Sjeremylt     }
16542b730f8bSJeremy L Thompson     CeedCall(CeedFree(&(*ceed)->obj_delegates));
1655aefd8378Sjeremylt   }
16560ace9bf2Sjeremylt 
16572b730f8bSJeremy L Thompson   if ((*ceed)->Destroy) CeedCall((*ceed)->Destroy(*ceed));
16580ace9bf2Sjeremylt 
165992ae7e47SJeremy L Thompson   for (CeedInt i = 0; i < (*ceed)->num_jit_source_roots; i++) {
16602b730f8bSJeremy L Thompson     CeedCall(CeedFree(&(*ceed)->jit_source_roots[i]));
1661032e71eaSJeremy L Thompson   }
16622b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*ceed)->jit_source_roots));
1663032e71eaSJeremy L Thompson 
16644753b775SJeremy L Thompson   for (CeedInt i = 0; i < (*ceed)->num_jit_defines; i++) {
16654753b775SJeremy L Thompson     CeedCall(CeedFree(&(*ceed)->jit_defines[i]));
16664753b775SJeremy L Thompson   }
16674753b775SJeremy L Thompson   CeedCall(CeedFree(&(*ceed)->jit_defines));
16684753b775SJeremy L Thompson 
1669898eb931SJeremy L Thompson   for (CeedInt i = 0; i < (*ceed)->num_rust_source_roots; i++) {
1670898eb931SJeremy L Thompson     CeedCall(CeedFree(&(*ceed)->rust_source_roots[i]));
1671898eb931SJeremy L Thompson   }
1672898eb931SJeremy L Thompson   CeedCall(CeedFree(&(*ceed)->rust_source_roots));
1673898eb931SJeremy L Thompson 
16742b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*ceed)->f_offsets));
16752b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*ceed)->resource));
16762b730f8bSJeremy L Thompson   CeedCall(CeedDestroy(&(*ceed)->op_fallback_ceed));
167773501bfeSJeremy L Thompson   CeedCall(CeedWorkVectorsDestroy(*ceed));
1678*b0f67a9cSJeremy L Thompson   CeedCall(CeedObjectDestroy(&(*ceed)->obj));
16792b730f8bSJeremy L Thompson   CeedCall(CeedFree(ceed));
1680e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1681d7b241e6Sjeremylt }
1682d7b241e6Sjeremylt 
1683f9982c62SWill Pazner // LCOV_EXCL_START
1684f9982c62SWill Pazner const char *CeedErrorFormat(Ceed ceed, const char *format, va_list *args) {
16852b730f8bSJeremy L Thompson   if (ceed->parent) return CeedErrorFormat(ceed->parent, format, args);
168678464608Sjeremylt   // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized
168778464608Sjeremylt   vsnprintf(ceed->err_msg, CEED_MAX_RESOURCE_LEN, format, *args);  // NOLINT
1688d1d35e2fSjeremylt   return ceed->err_msg;
1689f9982c62SWill Pazner }
1690f9982c62SWill Pazner // LCOV_EXCL_STOP
1691f9982c62SWill Pazner 
16927a982d89SJeremy L. Thompson /**
1693ca94c3ddSJeremy L Thompson   @brief Error handling implementation; use @ref CeedError() instead.
1694ca94c3ddSJeremy L Thompson 
1695ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
16967a982d89SJeremy L. Thompson 
16977a982d89SJeremy L. Thompson   @ref Developer
16987a982d89SJeremy L. Thompson **/
16992b730f8bSJeremy L Thompson int CeedErrorImpl(Ceed ceed, const char *filename, int lineno, const char *func, int ecode, const char *format, ...) {
17007a982d89SJeremy L. Thompson   va_list args;
1701d1d35e2fSjeremylt   int     ret_val;
17021c66c397SJeremy L Thompson 
17037a982d89SJeremy L. Thompson   va_start(args, format);
17047a982d89SJeremy L. Thompson   if (ceed) {
1705d1d35e2fSjeremylt     ret_val = ceed->Error(ceed, filename, lineno, func, ecode, format, &args);
17067a982d89SJeremy L. Thompson   } else {
1707b0d62198Sjeremylt     // LCOV_EXCL_START
1708477729cfSJeremy L Thompson     const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER");
17092b730f8bSJeremy L Thompson     if (!ceed_error_handler) ceed_error_handler = "abort";
1710bcbe1c99SJeremy L Thompson     if (!strcmp(ceed_error_handler, "return")) {
1711bcbe1c99SJeremy L Thompson       ret_val = CeedErrorReturn(ceed, filename, lineno, func, ecode, format, &args);
1712bcbe1c99SJeremy L Thompson     } else {
1713477729cfSJeremy L Thompson       // This function will not return
1714d1d35e2fSjeremylt       ret_val = CeedErrorAbort(ceed, filename, lineno, func, ecode, format, &args);
17157a982d89SJeremy L. Thompson     }
1716bcbe1c99SJeremy L Thompson   }
17177a982d89SJeremy L. Thompson   va_end(args);
1718d1d35e2fSjeremylt   return ret_val;
1719b0d62198Sjeremylt   // LCOV_EXCL_STOP
17207a982d89SJeremy L. Thompson }
17217a982d89SJeremy L. Thompson 
1722477729cfSJeremy L Thompson /**
1723477729cfSJeremy L Thompson   @brief Error handler that returns without printing anything.
1724477729cfSJeremy L Thompson 
1725ca94c3ddSJeremy L Thompson   Pass this to @ref CeedSetErrorHandler() to obtain this error handling behavior.
1726ca94c3ddSJeremy L Thompson 
1727ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1728477729cfSJeremy L Thompson 
1729477729cfSJeremy L Thompson   @ref Developer
1730477729cfSJeremy L Thompson **/
1731477729cfSJeremy L Thompson // LCOV_EXCL_START
17322b730f8bSJeremy L Thompson int CeedErrorReturn(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) {
1733d1d35e2fSjeremylt   return err_code;
1734477729cfSJeremy L Thompson }
1735477729cfSJeremy L Thompson // LCOV_EXCL_STOP
1736477729cfSJeremy L Thompson 
1737477729cfSJeremy L Thompson /**
1738ea61e9acSJeremy L Thompson   @brief Error handler that stores the error message for future use and returns the error.
1739477729cfSJeremy L Thompson 
1740ca94c3ddSJeremy L Thompson   Pass this to @ref CeedSetErrorHandler() to obtain this error handling behavior.
1741ca94c3ddSJeremy L Thompson 
1742ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1743477729cfSJeremy L Thompson 
1744477729cfSJeremy L Thompson   @ref Developer
1745477729cfSJeremy L Thompson **/
1746477729cfSJeremy L Thompson // LCOV_EXCL_START
17472b730f8bSJeremy L Thompson int CeedErrorStore(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) {
17482b730f8bSJeremy L Thompson   if (ceed->parent) return CeedErrorStore(ceed->parent, filename, line_no, func, err_code, format, args);
1749477729cfSJeremy L Thompson 
1750477729cfSJeremy L Thompson   // Build message
17511c66c397SJeremy L Thompson   int len = snprintf(ceed->err_msg, CEED_MAX_RESOURCE_LEN, "%s:%d in %s(): ", filename, line_no, func);
175278464608Sjeremylt   // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized
175378464608Sjeremylt   vsnprintf(ceed->err_msg + len, CEED_MAX_RESOURCE_LEN - len, format, *args);  // NOLINT
1754d1d35e2fSjeremylt   return err_code;
1755477729cfSJeremy L Thompson }
1756477729cfSJeremy L Thompson // LCOV_EXCL_STOP
1757477729cfSJeremy L Thompson 
1758477729cfSJeremy L Thompson /**
1759ca94c3ddSJeremy L Thompson   @brief Error handler that prints to `stderr` and aborts
1760477729cfSJeremy L Thompson 
1761ca94c3ddSJeremy L Thompson   Pass this to @ref CeedSetErrorHandler() to obtain this error handling behavior.
1762ca94c3ddSJeremy L Thompson 
1763ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1764477729cfSJeremy L Thompson 
1765477729cfSJeremy L Thompson   @ref Developer
1766477729cfSJeremy L Thompson **/
1767477729cfSJeremy L Thompson // LCOV_EXCL_START
17682b730f8bSJeremy L Thompson int CeedErrorAbort(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) {
1769d1d35e2fSjeremylt   fprintf(stderr, "%s:%d in %s(): ", filename, line_no, func);
1770f9982c62SWill Pazner   vfprintf(stderr, format, *args);
1771477729cfSJeremy L Thompson   fprintf(stderr, "\n");
1772477729cfSJeremy L Thompson   abort();
1773d1d35e2fSjeremylt   return err_code;
1774477729cfSJeremy L Thompson }
1775477729cfSJeremy L Thompson // LCOV_EXCL_STOP
1776477729cfSJeremy L Thompson 
1777477729cfSJeremy L Thompson /**
1778ca94c3ddSJeremy L Thompson   @brief Error handler that prints to `stderr` and exits.
1779477729cfSJeremy L Thompson 
1780ca94c3ddSJeremy L Thompson   Pass this to @ref CeedSetErrorHandler() to obtain this error handling behavior.
1781477729cfSJeremy L Thompson 
1782ca94c3ddSJeremy L Thompson   In contrast to @ref CeedErrorAbort(), this exits without a signal, so `atexit()` handlers (e.g., as used by gcov) are run.
1783ca94c3ddSJeremy L Thompson 
1784ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1785477729cfSJeremy L Thompson 
1786477729cfSJeremy L Thompson   @ref Developer
1787477729cfSJeremy L Thompson **/
17882b730f8bSJeremy L Thompson int CeedErrorExit(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) {
1789d1d35e2fSjeremylt   fprintf(stderr, "%s:%d in %s(): ", filename, line_no, func);
179078464608Sjeremylt   // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized
179178464608Sjeremylt   vfprintf(stderr, format, *args);  // NOLINT
1792477729cfSJeremy L Thompson   fprintf(stderr, "\n");
1793d1d35e2fSjeremylt   exit(err_code);
1794d1d35e2fSjeremylt   return err_code;
1795477729cfSJeremy L Thompson }
1796477729cfSJeremy L Thompson 
1797477729cfSJeremy L Thompson /**
1798477729cfSJeremy L Thompson   @brief Set error handler
1799477729cfSJeremy L Thompson 
1800ca94c3ddSJeremy L Thompson   A default error handler is set in @ref CeedInit().
1801ca94c3ddSJeremy L Thompson   Use this function to change the error handler to @ref CeedErrorReturn(), @ref CeedErrorAbort(), or a user-defined error handler.
1802ca94c3ddSJeremy L Thompson 
1803ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1804477729cfSJeremy L Thompson 
1805477729cfSJeremy L Thompson   @ref Developer
1806477729cfSJeremy L Thompson **/
1807d1d35e2fSjeremylt int CeedSetErrorHandler(Ceed ceed, CeedErrorHandler handler) {
1808d1d35e2fSjeremylt   ceed->Error = handler;
1809d1d35e2fSjeremylt   if (ceed->delegate) CeedSetErrorHandler(ceed->delegate, handler);
18102b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < ceed->obj_delegate_count; i++) CeedSetErrorHandler(ceed->obj_delegates[i].delegate, handler);
1811e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1812477729cfSJeremy L Thompson }
1813477729cfSJeremy L Thompson 
1814477729cfSJeremy L Thompson /**
1815477729cfSJeremy L Thompson   @brief Get error message
1816477729cfSJeremy L Thompson 
1817ca94c3ddSJeremy L Thompson   The error message is only stored when using the error handler @ref CeedErrorStore()
1818477729cfSJeremy L Thompson 
1819ca94c3ddSJeremy L Thompson   @param[in]  ceed    `Ceed` context to retrieve error message
1820d1d35e2fSjeremylt   @param[out] err_msg Char pointer to hold error message
1821477729cfSJeremy L Thompson 
1822ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1823ca94c3ddSJeremy L Thompson 
1824477729cfSJeremy L Thompson   @ref Developer
1825477729cfSJeremy L Thompson **/
1826d1d35e2fSjeremylt int CeedGetErrorMessage(Ceed ceed, const char **err_msg) {
18272b730f8bSJeremy L Thompson   if (ceed->parent) return CeedGetErrorMessage(ceed->parent, err_msg);
1828d1d35e2fSjeremylt   *err_msg = ceed->err_msg;
1829e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1830477729cfSJeremy L Thompson }
1831477729cfSJeremy L Thompson 
1832477729cfSJeremy L Thompson /**
1833ca94c3ddSJeremy L Thompson   @brief Restore error message.
1834477729cfSJeremy L Thompson 
1835ca94c3ddSJeremy L Thompson   The error message is only stored when using the error handler @ref CeedErrorStore().
1836477729cfSJeremy L Thompson 
1837ca94c3ddSJeremy L Thompson   @param[in]  ceed    `Ceed` context to restore error message
1838d1d35e2fSjeremylt   @param[out] err_msg Char pointer that holds error message
1839477729cfSJeremy L Thompson 
1840ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1841ca94c3ddSJeremy L Thompson 
1842477729cfSJeremy L Thompson   @ref Developer
1843477729cfSJeremy L Thompson **/
1844d1d35e2fSjeremylt int CeedResetErrorMessage(Ceed ceed, const char **err_msg) {
18452b730f8bSJeremy L Thompson   if (ceed->parent) return CeedResetErrorMessage(ceed->parent, err_msg);
1846d1d35e2fSjeremylt   *err_msg = NULL;
1847d1d35e2fSjeremylt   memcpy(ceed->err_msg, "No error message stored", 24);
1848e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1849477729cfSJeremy L Thompson }
1850477729cfSJeremy L Thompson 
18511070991dSJed Brown /**
1852ca94c3ddSJeremy L Thompson   @brief Get libCEED library version information.
18531070991dSJed Brown 
1854ea61e9acSJeremy L Thompson   libCEED version numbers have the form major.minor.patch.
1855ea61e9acSJeremy L Thompson   Non-release versions may contain unstable interfaces.
18561070991dSJed Brown 
18571070991dSJed Brown   @param[out] major   Major version of the library
18581070991dSJed Brown   @param[out] minor   Minor version of the library
18591070991dSJed Brown   @param[out] patch   Patch (subminor) version of the library
186053cbfc38SJeremy L Thompson   @param[out] release True for releases; false for development branches
18611070991dSJed Brown 
1862ca94c3ddSJeremy L Thompson   The caller may pass `NULL` for any arguments that are not needed.
18631070991dSJed Brown 
1864ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
18651070991dSJed Brown 
18661070991dSJed Brown   @ref Developer
1867ca94c3ddSJeremy L Thompson 
18684f69910bSJed Brown   @sa CEED_VERSION_GE() CeedGetGitVersion() CeedGetBuildConfiguration()
18691070991dSJed Brown */
18701070991dSJed Brown int CeedGetVersion(int *major, int *minor, int *patch, bool *release) {
18711070991dSJed Brown   if (major) *major = CEED_VERSION_MAJOR;
18721070991dSJed Brown   if (minor) *minor = CEED_VERSION_MINOR;
18731070991dSJed Brown   if (patch) *patch = CEED_VERSION_PATCH;
18741070991dSJed Brown   if (release) *release = CEED_VERSION_RELEASE;
1875ca94c3ddSJeremy L Thompson   return CEED_ERROR_SUCCESS;
18761070991dSJed Brown }
18771070991dSJed Brown 
187853cbfc38SJeremy L Thompson /**
187953cbfc38SJeremy L Thompson   @brief Get libCEED scalar type, such as F64 or F32
188053cbfc38SJeremy L Thompson 
188153cbfc38SJeremy L Thompson   @param[out] scalar_type Type of libCEED scalars
188253cbfc38SJeremy L Thompson 
1883ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1884ca94c3ddSJeremy L Thompson 
188553cbfc38SJeremy L Thompson   @ref Developer
188653cbfc38SJeremy L Thompson */
188780a9ef05SNatalie Beams int CeedGetScalarType(CeedScalarType *scalar_type) {
188880a9ef05SNatalie Beams   *scalar_type = CEED_SCALAR_TYPE;
1889ca94c3ddSJeremy L Thompson   return CEED_ERROR_SUCCESS;
189080a9ef05SNatalie Beams }
189180a9ef05SNatalie Beams 
1892d7b241e6Sjeremylt /// @}
1893