xref: /libCEED/rust/libceed-sys/c-src/interface/ceed.c (revision ca38d01d95e1d63e8425c25ab66131b07bd24aa2)
1d275d636SJeremy L Thompson // Copyright (c) 2017-2025, 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");
16873501bfeSJeremy L Thompson     ceed->ref_count += 2;  // Note: increase ref_count to prevent Ceed destructor from triggering again
16973501bfeSJeremy L Thompson     CeedCall(CeedVectorDestroy(&ceed->work_vectors->vecs[i]));
17073501bfeSJeremy L Thompson     ceed->ref_count -= 1;  // Note: restore ref_count
17173501bfeSJeremy L Thompson   }
17273501bfeSJeremy L Thompson   CeedCall(CeedFree(&ceed->work_vectors->is_in_use));
17373501bfeSJeremy L Thompson   CeedCall(CeedFree(&ceed->work_vectors->vecs));
17473501bfeSJeremy L Thompson   CeedCall(CeedFree(&ceed->work_vectors));
17573501bfeSJeremy L Thompson   return CEED_ERROR_SUCCESS;
17673501bfeSJeremy L Thompson }
17773501bfeSJeremy L Thompson 
1787a982d89SJeremy L. Thompson /// @}
179d7b241e6Sjeremylt 
1807a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
1817a982d89SJeremy L. Thompson /// Ceed Backend API
1827a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
1837a982d89SJeremy L. Thompson /// @addtogroup CeedBackend
1847a982d89SJeremy L. Thompson /// @{
185d7b241e6Sjeremylt 
186b11c1e72Sjeremylt /**
187ca94c3ddSJeremy L Thompson   @brief Return value of `CEED_DEBUG` environment variable
18860f9e2d6SJeremy L Thompson 
189ca94c3ddSJeremy L Thompson   @param[in] ceed `Ceed` context
19060f9e2d6SJeremy L Thompson 
191ca94c3ddSJeremy L Thompson   @return Boolean value: true  - debugging mode enabled
1923f21f6b1SJeremy L Thompson                          false - debugging mode disabled
19360f9e2d6SJeremy L Thompson 
19460f9e2d6SJeremy L Thompson   @ref Backend
19560f9e2d6SJeremy L Thompson **/
196fc6bbcedSJeremy L Thompson // LCOV_EXCL_START
1972b730f8bSJeremy L Thompson bool CeedDebugFlag(const Ceed ceed) { return ceed->is_debug; }
198fc6bbcedSJeremy L Thompson // LCOV_EXCL_STOP
19960f9e2d6SJeremy L Thompson 
20060f9e2d6SJeremy L Thompson /**
201ca94c3ddSJeremy L Thompson   @brief Return value of `CEED_DEBUG` environment variable
20260f9e2d6SJeremy L Thompson 
203ca94c3ddSJeremy L Thompson   @return Boolean value: true  - debugging mode enabled
2043f21f6b1SJeremy L Thompson                          false - debugging mode disabled
2053f21f6b1SJeremy L Thompson 
2063f21f6b1SJeremy L Thompson   @ref Backend
2073f21f6b1SJeremy L Thompson **/
2083f21f6b1SJeremy L Thompson // LCOV_EXCL_START
2091c66c397SJeremy L Thompson bool CeedDebugFlagEnv(void) { return getenv("CEED_DEBUG") || getenv("DEBUG") || getenv("DBG"); }
2103f21f6b1SJeremy L Thompson // LCOV_EXCL_STOP
2113f21f6b1SJeremy L Thompson 
2123f21f6b1SJeremy L Thompson /**
2133f21f6b1SJeremy L Thompson   @brief Print debugging information in color
2143f21f6b1SJeremy L Thompson 
215ca94c3ddSJeremy L Thompson   @param[in] color  Color to print
216ca94c3ddSJeremy L Thompson   @param[in] format Printing format
21760f9e2d6SJeremy L Thompson 
21860f9e2d6SJeremy L Thompson   @ref Backend
21960f9e2d6SJeremy L Thompson **/
220fc6bbcedSJeremy L Thompson // LCOV_EXCL_START
2213f21f6b1SJeremy L Thompson void CeedDebugImpl256(const unsigned char color, const char *format, ...) {
22260f9e2d6SJeremy L Thompson   va_list args;
22360f9e2d6SJeremy L Thompson   va_start(args, format);
22460f9e2d6SJeremy L Thompson   fflush(stdout);
2252b730f8bSJeremy L Thompson   if (color != CEED_DEBUG_COLOR_NONE) fprintf(stdout, "\033[38;5;%dm", color);
22660f9e2d6SJeremy L Thompson   vfprintf(stdout, format, args);
2272b730f8bSJeremy L Thompson   if (color != CEED_DEBUG_COLOR_NONE) fprintf(stdout, "\033[m");
22860f9e2d6SJeremy L Thompson   fprintf(stdout, "\n");
22960f9e2d6SJeremy L Thompson   fflush(stdout);
23060f9e2d6SJeremy L Thompson   va_end(args);
23160f9e2d6SJeremy L Thompson }
232fc6bbcedSJeremy L Thompson // LCOV_EXCL_STOP
23360f9e2d6SJeremy L Thompson 
23460f9e2d6SJeremy L Thompson /**
235ca94c3ddSJeremy L Thompson   @brief Allocate an array on the host; use @ref CeedMalloc().
236b11c1e72Sjeremylt 
237ea61e9acSJeremy L Thompson   Memory usage can be tracked by the library.
238ea61e9acSJeremy L Thompson   This ensures sufficient alignment for vectorization and should be used for large allocations.
239b11c1e72Sjeremylt 
240ea61e9acSJeremy L Thompson   @param[in]  n    Number of units to allocate
241ea61e9acSJeremy L Thompson   @param[in]  unit Size of each unit
242ca94c3ddSJeremy L Thompson   @param[out] p    Address of pointer to hold the result
243b11c1e72Sjeremylt 
244b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
245b11c1e72Sjeremylt 
2467a982d89SJeremy L. Thompson   @ref Backend
247ca94c3ddSJeremy L Thompson 
248ca94c3ddSJeremy L Thompson   @sa CeedFree()
249b11c1e72Sjeremylt **/
250d7b241e6Sjeremylt int CeedMallocArray(size_t n, size_t unit, void *p) {
251d7b241e6Sjeremylt   int ierr = posix_memalign((void **)p, CEED_ALIGN, n * unit);
2526574a04fSJeremy L Thompson   CeedCheck(ierr == 0, NULL, CEED_ERROR_MAJOR, "posix_memalign failed to allocate %zd members of size %zd\n", n, unit);
253e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
254d7b241e6Sjeremylt }
255d7b241e6Sjeremylt 
256b11c1e72Sjeremylt /**
257ca94c3ddSJeremy L Thompson   @brief Allocate a cleared (zeroed) array on the host; use @ref CeedCalloc().
258b11c1e72Sjeremylt 
259b11c1e72Sjeremylt   Memory usage can be tracked by the library.
260b11c1e72Sjeremylt 
261ea61e9acSJeremy L Thompson   @param[in]  n    Number of units to allocate
262ea61e9acSJeremy L Thompson   @param[in]  unit Size of each unit
263ca94c3ddSJeremy L Thompson   @param[out] p    Address of pointer to hold the result
264b11c1e72Sjeremylt 
265b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
266b11c1e72Sjeremylt 
2677a982d89SJeremy L. Thompson   @ref Backend
268ca94c3ddSJeremy L Thompson 
269ca94c3ddSJeremy L Thompson   @sa CeedFree()
270b11c1e72Sjeremylt **/
271d7b241e6Sjeremylt int CeedCallocArray(size_t n, size_t unit, void *p) {
272d7b241e6Sjeremylt   *(void **)p = calloc(n, unit);
2736574a04fSJeremy L Thompson   CeedCheck(!n || !unit || *(void **)p, NULL, CEED_ERROR_MAJOR, "calloc failed to allocate %zd members of size %zd\n", n, unit);
274e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
275d7b241e6Sjeremylt }
276d7b241e6Sjeremylt 
277b11c1e72Sjeremylt /**
278ca94c3ddSJeremy L Thompson   @brief Reallocate an array on the host; use @ref CeedRealloc().
279b11c1e72Sjeremylt 
280b11c1e72Sjeremylt   Memory usage can be tracked by the library.
281b11c1e72Sjeremylt 
282ea61e9acSJeremy L Thompson   @param[in]  n    Number of units to allocate
283ea61e9acSJeremy L Thompson   @param[in]  unit Size of each unit
284ca94c3ddSJeremy L Thompson   @param[out] p    Address of pointer to hold the result
285b11c1e72Sjeremylt 
286b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
287b11c1e72Sjeremylt 
2887a982d89SJeremy L. Thompson   @ref Backend
289ca94c3ddSJeremy L Thompson 
290ca94c3ddSJeremy L Thompson   @sa CeedFree()
291b11c1e72Sjeremylt **/
292d7b241e6Sjeremylt int CeedReallocArray(size_t n, size_t unit, void *p) {
293d7b241e6Sjeremylt   *(void **)p = realloc(*(void **)p, n * unit);
2946574a04fSJeremy L Thompson   CeedCheck(!n || !unit || *(void **)p, NULL, CEED_ERROR_MAJOR, "realloc failed to allocate %zd members of size %zd\n", n, unit);
295e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
296d7b241e6Sjeremylt }
297d7b241e6Sjeremylt 
298f7e22acaSJeremy L Thompson /**
299ca94c3ddSJeremy L Thompson   @brief Allocate a cleared string buffer on the host.
300f7e22acaSJeremy L Thompson 
301f7e22acaSJeremy L Thompson   Memory usage can be tracked by the library.
302f7e22acaSJeremy L Thompson 
303ea61e9acSJeremy L Thompson   @param[in]  source Pointer to string to be copied
304ea61e9acSJeremy L Thompson   @param[out] copy   Pointer to variable to hold newly allocated string copy
305f7e22acaSJeremy L Thompson 
306f7e22acaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
307f7e22acaSJeremy L Thompson 
308f7e22acaSJeremy L Thompson   @ref Backend
309ca94c3ddSJeremy L Thompson 
310ca94c3ddSJeremy L Thompson   @sa CeedFree()
311f7e22acaSJeremy L Thompson **/
312f7e22acaSJeremy L Thompson int CeedStringAllocCopy(const char *source, char **copy) {
313f7e22acaSJeremy L Thompson   size_t len = strlen(source);
3142b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(len + 1, copy));
315d602d780SJeremy L Thompson   memcpy(*copy, source, len);
316f7e22acaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
317f7e22acaSJeremy L Thompson }
318f7e22acaSJeremy L Thompson 
319ca94c3ddSJeremy L Thompson /** Free memory allocated using @ref CeedMalloc() or @ref CeedCalloc()
32034138859Sjeremylt 
321ca94c3ddSJeremy L Thompson   @param[in,out] p Address of pointer to memory.
322ca94c3ddSJeremy 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.
323ca94c3ddSJeremy L Thompson 
324ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
325ca94c3ddSJeremy L Thompson 
326ca94c3ddSJeremy L Thompson   @ref Backend
32734138859Sjeremylt **/
328d7b241e6Sjeremylt int CeedFree(void *p) {
329d7b241e6Sjeremylt   free(*(void **)p);
330d7b241e6Sjeremylt   *(void **)p = NULL;
331e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
332d7b241e6Sjeremylt }
333d7b241e6Sjeremylt 
334f5d1e504SJeremy L Thompson /** Internal helper to manage handoff of user `source_array` to backend with proper @ref CeedCopyMode behavior.
335f5d1e504SJeremy L Thompson 
336f5d1e504SJeremy L Thompson   @param[in]     source_array          Source data provided by user
337f5d1e504SJeremy L Thompson   @param[in]     copy_mode             Copy mode for the data
338f5d1e504SJeremy L Thompson   @param[in]     num_values            Number of values to handle
33917afdf5cSJames Wright   @param[in]     size_unit             Size of array element in bytes
340f5d1e504SJeremy L Thompson   @param[in,out] target_array_owned    Pointer to location to allocated or hold owned data, may be freed if already allocated
341f5d1e504SJeremy L Thompson   @param[out]    target_array_borrowed Pointer to location to hold borrowed data
342f5d1e504SJeremy L Thompson   @param[out]    target_array          Pointer to location for data
343f5d1e504SJeremy L Thompson 
344f5d1e504SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
345f5d1e504SJeremy L Thompson 
346f5d1e504SJeremy L Thompson   @ref Backend
347f5d1e504SJeremy L Thompson **/
348f5d1e504SJeremy L Thompson static inline int CeedSetHostGenericArray(const void *source_array, CeedCopyMode copy_mode, size_t size_unit, CeedSize num_values,
349f5d1e504SJeremy L Thompson                                           void *target_array_owned, void *target_array_borrowed, void *target_array) {
350f5d1e504SJeremy L Thompson   switch (copy_mode) {
351f5d1e504SJeremy L Thompson     case CEED_COPY_VALUES:
352cc3bdf8cSJeremy L Thompson       if (!*(void **)target_array) {
353cc3bdf8cSJeremy L Thompson         if (*(void **)target_array_borrowed) {
354cc3bdf8cSJeremy L Thompson           *(void **)target_array = *(void **)target_array_borrowed;
355cc3bdf8cSJeremy L Thompson         } else {
356f5d1e504SJeremy L Thompson           if (!*(void **)target_array_owned) CeedCall(CeedCallocArray(num_values, size_unit, target_array_owned));
357f5d1e504SJeremy L Thompson           *(void **)target_array = *(void **)target_array_owned;
358cc3bdf8cSJeremy L Thompson         }
359cc3bdf8cSJeremy L Thompson       }
360cc3bdf8cSJeremy L Thompson       if (source_array) memcpy(*(void **)target_array, source_array, size_unit * num_values);
361f5d1e504SJeremy L Thompson       break;
362f5d1e504SJeremy L Thompson     case CEED_OWN_POINTER:
363f5d1e504SJeremy L Thompson       CeedCall(CeedFree(target_array_owned));
364f5d1e504SJeremy L Thompson       *(void **)target_array_owned    = (void *)source_array;
365f5d1e504SJeremy L Thompson       *(void **)target_array_borrowed = NULL;
366f5d1e504SJeremy L Thompson       *(void **)target_array          = *(void **)target_array_owned;
367f5d1e504SJeremy L Thompson       break;
368f5d1e504SJeremy L Thompson     case CEED_USE_POINTER:
369f5d1e504SJeremy L Thompson       CeedCall(CeedFree(target_array_owned));
370f5d1e504SJeremy L Thompson       *(void **)target_array_owned    = NULL;
371f5d1e504SJeremy L Thompson       *(void **)target_array_borrowed = (void *)source_array;
372f5d1e504SJeremy L Thompson       *(void **)target_array          = *(void **)target_array_borrowed;
373f5d1e504SJeremy L Thompson   }
374f5d1e504SJeremy L Thompson   return CEED_ERROR_SUCCESS;
375f5d1e504SJeremy L Thompson }
376f5d1e504SJeremy L Thompson 
377f5d1e504SJeremy L Thompson /** Manage handoff of user `bool` `source_array` to backend with proper @ref CeedCopyMode behavior.
378f5d1e504SJeremy L Thompson 
379f5d1e504SJeremy L Thompson   @param[in]     source_array          Source data provided by user
380f5d1e504SJeremy L Thompson   @param[in]     copy_mode             Copy mode for the data
381f5d1e504SJeremy L Thompson   @param[in]     num_values            Number of values to handle
382f5d1e504SJeremy L Thompson   @param[in,out] target_array_owned    Pointer to location to allocated or hold owned data, may be freed if already allocated
383f5d1e504SJeremy L Thompson   @param[out]    target_array_borrowed Pointer to location to hold borrowed data
384f5d1e504SJeremy L Thompson   @param[out]    target_array          Pointer to location for data
385f5d1e504SJeremy L Thompson 
386f5d1e504SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
387f5d1e504SJeremy L Thompson 
388f5d1e504SJeremy L Thompson   @ref Backend
389f5d1e504SJeremy L Thompson **/
390f5d1e504SJeremy L Thompson int CeedSetHostBoolArray(const bool *source_array, CeedCopyMode copy_mode, CeedSize num_values, const bool **target_array_owned,
391f5d1e504SJeremy L Thompson                          const bool **target_array_borrowed, const bool **target_array) {
392f5d1e504SJeremy L Thompson   CeedCall(CeedSetHostGenericArray(source_array, copy_mode, sizeof(bool), num_values, target_array_owned, target_array_borrowed, target_array));
393f5d1e504SJeremy L Thompson   return CEED_ERROR_SUCCESS;
394f5d1e504SJeremy L Thompson }
395f5d1e504SJeremy L Thompson 
396f5d1e504SJeremy L Thompson /** Manage handoff of user `CeedInt8` `source_array` to backend with proper @ref CeedCopyMode behavior.
397f5d1e504SJeremy L Thompson 
398f5d1e504SJeremy L Thompson   @param[in]     source_array          Source data provided by user
399f5d1e504SJeremy L Thompson   @param[in]     copy_mode             Copy mode for the data
400f5d1e504SJeremy L Thompson   @param[in]     num_values            Number of values to handle
401f5d1e504SJeremy L Thompson   @param[in,out] target_array_owned    Pointer to location to allocated or hold owned data, may be freed if already allocated
402f5d1e504SJeremy L Thompson   @param[out]    target_array_borrowed Pointer to location to hold borrowed data
403f5d1e504SJeremy L Thompson   @param[out]    target_array          Pointer to location for data
404f5d1e504SJeremy L Thompson 
405f5d1e504SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
406f5d1e504SJeremy L Thompson 
407f5d1e504SJeremy L Thompson   @ref Backend
408f5d1e504SJeremy L Thompson **/
409f5d1e504SJeremy L Thompson int CeedSetHostCeedInt8Array(const CeedInt8 *source_array, CeedCopyMode copy_mode, CeedSize num_values, const CeedInt8 **target_array_owned,
410f5d1e504SJeremy L Thompson                              const CeedInt8 **target_array_borrowed, const CeedInt8 **target_array) {
411f5d1e504SJeremy L Thompson   CeedCall(CeedSetHostGenericArray(source_array, copy_mode, sizeof(CeedInt8), num_values, target_array_owned, target_array_borrowed, target_array));
412f5d1e504SJeremy L Thompson   return CEED_ERROR_SUCCESS;
413f5d1e504SJeremy L Thompson }
414f5d1e504SJeremy L Thompson 
415f5d1e504SJeremy L Thompson /** Manage handoff of user `CeedInt` `source_array` to backend with proper @ref CeedCopyMode behavior.
416f5d1e504SJeremy L Thompson 
417f5d1e504SJeremy L Thompson   @param[in]     source_array          Source data provided by user
418f5d1e504SJeremy L Thompson   @param[in]     copy_mode             Copy mode for the data
419f5d1e504SJeremy L Thompson   @param[in]     num_values            Number of values to handle
420f5d1e504SJeremy L Thompson   @param[in,out] target_array_owned    Pointer to location to allocated or hold owned data, may be freed if already allocated
421f5d1e504SJeremy L Thompson   @param[out]    target_array_borrowed Pointer to location to hold borrowed data
422f5d1e504SJeremy L Thompson   @param[out]    target_array          Pointer to location for data
423f5d1e504SJeremy L Thompson 
424f5d1e504SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
425f5d1e504SJeremy L Thompson 
426f5d1e504SJeremy L Thompson   @ref Backend
427f5d1e504SJeremy L Thompson **/
428f5d1e504SJeremy L Thompson int CeedSetHostCeedIntArray(const CeedInt *source_array, CeedCopyMode copy_mode, CeedSize num_values, const CeedInt **target_array_owned,
429f5d1e504SJeremy L Thompson                             const CeedInt **target_array_borrowed, const CeedInt **target_array) {
430f5d1e504SJeremy L Thompson   CeedCall(CeedSetHostGenericArray(source_array, copy_mode, sizeof(CeedInt), num_values, target_array_owned, target_array_borrowed, target_array));
431f5d1e504SJeremy L Thompson   return CEED_ERROR_SUCCESS;
432f5d1e504SJeremy L Thompson }
433f5d1e504SJeremy L Thompson 
434f5d1e504SJeremy L Thompson /** Manage handoff of user `CeedScalar` `source_array` to backend with proper @ref CeedCopyMode behavior.
435f5d1e504SJeremy L Thompson 
436f5d1e504SJeremy L Thompson   @param[in]     source_array          Source data provided by user
437f5d1e504SJeremy L Thompson   @param[in]     copy_mode             Copy mode for the data
438f5d1e504SJeremy L Thompson   @param[in]     num_values            Number of values to handle
439f5d1e504SJeremy L Thompson   @param[in,out] target_array_owned    Pointer to location to allocated or hold owned data, may be freed if already allocated
440f5d1e504SJeremy L Thompson   @param[out]    target_array_borrowed Pointer to location to hold borrowed data
441f5d1e504SJeremy L Thompson   @param[out]    target_array          Pointer to location for data
442f5d1e504SJeremy L Thompson 
443f5d1e504SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
444f5d1e504SJeremy L Thompson 
445f5d1e504SJeremy L Thompson   @ref Backend
446f5d1e504SJeremy L Thompson **/
447f5d1e504SJeremy L Thompson int CeedSetHostCeedScalarArray(const CeedScalar *source_array, CeedCopyMode copy_mode, CeedSize num_values, const CeedScalar **target_array_owned,
448f5d1e504SJeremy L Thompson                                const CeedScalar **target_array_borrowed, const CeedScalar **target_array) {
449f5d1e504SJeremy L Thompson   CeedCall(CeedSetHostGenericArray(source_array, copy_mode, sizeof(CeedScalar), num_values, target_array_owned, target_array_borrowed, target_array));
450f5d1e504SJeremy L Thompson   return CEED_ERROR_SUCCESS;
451f5d1e504SJeremy L Thompson }
452f5d1e504SJeremy L Thompson 
453d7b241e6Sjeremylt /**
454ca94c3ddSJeremy L Thompson   @brief Register a `Ceed` backend
455d7b241e6Sjeremylt 
456ea61e9acSJeremy L Thompson   @param[in] prefix   Prefix of resources for this backend to respond to.
457ea61e9acSJeremy L Thompson                         For example, the reference backend responds to "/cpu/self".
458ca94c3ddSJeremy L Thompson   @param[in] init     Initialization function called by @ref CeedInit() when the backend is selected to drive the requested resource
459ea61e9acSJeremy L Thompson   @param[in] priority Integer priority.
460ca94c3ddSJeremy L Thompson                         Lower values are preferred in case the resource requested by @ref CeedInit() has non-unique best prefix match.
461b11c1e72Sjeremylt 
462b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
463dfdf5a53Sjeremylt 
4647a982d89SJeremy L. Thompson   @ref Backend
465b11c1e72Sjeremylt **/
4662b730f8bSJeremy L Thompson int CeedRegister(const char *prefix, int (*init)(const char *, Ceed), unsigned int priority) {
46710243053SJeremy L Thompson   CeedDebugEnv("Backend Register: %s", prefix);
4686a406739SJeremy L Thompson   CeedRegisterImpl(prefix, init, priority);
469e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
470d7b241e6Sjeremylt }
471d7b241e6Sjeremylt 
472b11c1e72Sjeremylt /**
47360f9e2d6SJeremy L Thompson   @brief Return debugging status flag
47460f9e2d6SJeremy L Thompson 
475ca94c3ddSJeremy L Thompson   @param[in]  ceed     `Ceed` context to get debugging flag
476ea61e9acSJeremy L Thompson   @param[out] is_debug Variable to store debugging flag
47760f9e2d6SJeremy L Thompson 
47860f9e2d6SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
47960f9e2d6SJeremy L Thompson 
480d1d35e2fSjeremylt   @ref Backend
48160f9e2d6SJeremy L Thompson **/
482d1d35e2fSjeremylt int CeedIsDebug(Ceed ceed, bool *is_debug) {
4833f21f6b1SJeremy L Thompson   *is_debug = ceed->is_debug;
484e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
48560f9e2d6SJeremy L Thompson }
48660f9e2d6SJeremy L Thompson 
48760f9e2d6SJeremy L Thompson /**
488bf84744cSJeremy L Thompson   @brief Get the root of the requested resource.
489bf84744cSJeremy L Thompson 
490bf84744cSJeremy L Thompson   Note: Caller is responsible for calling @ref CeedFree() on the `resource_root`.
491bc246734SJeremy L Thompson 
492ca94c3ddSJeremy L Thompson   @param[in]  ceed          `Ceed` context to get resource name of
493ca94c3ddSJeremy L Thompson   @param[in]  resource      Full user specified resource
494ca94c3ddSJeremy L Thompson   @param[in]  delineator    Delineator to break `resource_root` and `resource_spec`
495bc246734SJeremy L Thompson   @param[out] resource_root Variable to store resource root
496bc246734SJeremy L Thompson 
497bc246734SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
498bc246734SJeremy L Thompson 
499bc246734SJeremy L Thompson   @ref Backend
500bc246734SJeremy L Thompson **/
501bc246734SJeremy L Thompson int CeedGetResourceRoot(Ceed ceed, const char *resource, const char *delineator, char **resource_root) {
502bc246734SJeremy L Thompson   char  *device_spec       = strstr(resource, delineator);
503bc246734SJeremy L Thompson   size_t resource_root_len = device_spec ? (size_t)(device_spec - resource) + 1 : strlen(resource) + 1;
5041c66c397SJeremy L Thompson 
505bc246734SJeremy L Thompson   CeedCall(CeedCalloc(resource_root_len, resource_root));
506bc246734SJeremy L Thompson   memcpy(*resource_root, resource, resource_root_len - 1);
507bc246734SJeremy L Thompson   return CEED_ERROR_SUCCESS;
508bc246734SJeremy L Thompson }
509bc246734SJeremy L Thompson 
510bc246734SJeremy L Thompson /**
511ca94c3ddSJeremy L Thompson   @brief Retrieve a parent `Ceed` context
5127a982d89SJeremy L. Thompson 
513ca94c3ddSJeremy L Thompson   @param[in]  ceed   `Ceed` context to retrieve parent of
5147a982d89SJeremy L. Thompson   @param[out] parent Address to save the parent to
5157a982d89SJeremy L. Thompson 
5167a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5177a982d89SJeremy L. Thompson 
5187a982d89SJeremy L. Thompson   @ref Backend
5197a982d89SJeremy L. Thompson **/
5207a982d89SJeremy L. Thompson int CeedGetParent(Ceed ceed, Ceed *parent) {
5217a982d89SJeremy L. Thompson   if (ceed->parent) {
5222b730f8bSJeremy L Thompson     CeedCall(CeedGetParent(ceed->parent, parent));
523e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
5247a982d89SJeremy L. Thompson   }
5259bc66399SJeremy L Thompson   *parent = NULL;
5269bc66399SJeremy L Thompson   CeedCall(CeedReferenceCopy(ceed, parent));
527e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5287a982d89SJeremy L. Thompson }
5297a982d89SJeremy L. Thompson 
5307a982d89SJeremy L. Thompson /**
531ca94c3ddSJeremy L Thompson   @brief Retrieve a delegate `Ceed` context
5327a982d89SJeremy L. Thompson 
533ca94c3ddSJeremy L Thompson   @param[in]  ceed     `Ceed` context to retrieve delegate of
5347a982d89SJeremy L. Thompson   @param[out] delegate Address to save the delegate to
5357a982d89SJeremy L. Thompson 
5367a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5377a982d89SJeremy L. Thompson 
5387a982d89SJeremy L. Thompson   @ref Backend
5397a982d89SJeremy L. Thompson **/
5407a982d89SJeremy L. Thompson int CeedGetDelegate(Ceed ceed, Ceed *delegate) {
5419bc66399SJeremy L Thompson   *delegate = NULL;
5429bc66399SJeremy L Thompson   if (ceed->delegate) CeedCall(CeedReferenceCopy(ceed->delegate, delegate));
543e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5447a982d89SJeremy L. Thompson }
5457a982d89SJeremy L. Thompson 
5467a982d89SJeremy L. Thompson /**
547ca94c3ddSJeremy L Thompson   @brief Set a delegate `Ceed` context
5487a982d89SJeremy L. Thompson 
549ca94c3ddSJeremy L Thompson   This function allows a `Ceed` context to set a delegate `Ceed` context.
550ca94c3ddSJeremy L Thompson   All backend implementations default to the delegate `Ceed` context, unless overridden.
5517a982d89SJeremy L. Thompson 
552ca94c3ddSJeremy L Thompson   @param[in]  ceed     `Ceed` context to set delegate of
5537a982d89SJeremy L. Thompson   @param[out] delegate Address to set the delegate to
5547a982d89SJeremy L. Thompson 
5557a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5567a982d89SJeremy L. Thompson 
5577a982d89SJeremy L. Thompson   @ref Backend
5587a982d89SJeremy L. Thompson **/
5597a982d89SJeremy L. Thompson int CeedSetDelegate(Ceed ceed, Ceed delegate) {
5609bc66399SJeremy L Thompson   CeedCall(CeedReferenceCopy(delegate, &ceed->delegate));
5617a982d89SJeremy L. Thompson   delegate->parent = ceed;
562e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5637a982d89SJeremy L. Thompson }
5647a982d89SJeremy L. Thompson 
5657a982d89SJeremy L. Thompson /**
566ca94c3ddSJeremy L Thompson   @brief Retrieve a delegate `Ceed` context for a specific object type
5677a982d89SJeremy L. Thompson 
568ca94c3ddSJeremy L Thompson   @param[in]  ceed     `Ceed` context to retrieve delegate of
5697a982d89SJeremy L. Thompson   @param[out] delegate Address to save the delegate to
570d1d35e2fSjeremylt   @param[in]  obj_name Name of the object type to retrieve delegate for
5717a982d89SJeremy L. Thompson 
5727a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5737a982d89SJeremy L. Thompson 
5747a982d89SJeremy L. Thompson   @ref Backend
5757a982d89SJeremy L. Thompson **/
576d1d35e2fSjeremylt int CeedGetObjectDelegate(Ceed ceed, Ceed *delegate, const char *obj_name) {
5777a982d89SJeremy L. Thompson   // Check for object delegate
5782b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < ceed->obj_delegate_count; i++) {
579d1d35e2fSjeremylt     if (!strcmp(obj_name, ceed->obj_delegates->obj_name)) {
5809bc66399SJeremy L Thompson       *delegate = NULL;
5819bc66399SJeremy L Thompson       CeedCall(CeedReferenceCopy(ceed->obj_delegates->delegate, delegate));
582e15f9bd0SJeremy L Thompson       return CEED_ERROR_SUCCESS;
5837a982d89SJeremy L. Thompson     }
5842b730f8bSJeremy L Thompson   }
5857a982d89SJeremy L. Thompson 
5867a982d89SJeremy L. Thompson   // Use default delegate if no object delegate
5872b730f8bSJeremy L Thompson   CeedCall(CeedGetDelegate(ceed, delegate));
588e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5897a982d89SJeremy L. Thompson }
5907a982d89SJeremy L. Thompson 
5917a982d89SJeremy L. Thompson /**
592ca94c3ddSJeremy L Thompson   @brief Set a delegate `Ceed` context for a specific object type
5937a982d89SJeremy L. Thompson 
594ca94c3ddSJeremy L Thompson   This function allows a `Ceed` context to set a delegate `Ceed` context for a given type of `Ceed` object.
595ca94c3ddSJeremy L Thompson   All backend implementations default to the delegate `Ceed` context for this object.
596ca94c3ddSJeremy L Thompson   For example, `CeedSetObjectDelegate(ceed, delegate, "Basis")` uses delegate implementations for all `CeedBasis` backend functions.
5977a982d89SJeremy L. Thompson 
598ca94c3ddSJeremy L Thompson   @param[in,out] ceed     `Ceed` context to set delegate of
599ca94c3ddSJeremy L Thompson   @param[in]     delegate `Ceed` context to use for delegation
600d1d35e2fSjeremylt   @param[in]     obj_name Name of the object type to set delegate for
6017a982d89SJeremy L. Thompson 
6027a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6037a982d89SJeremy L. Thompson 
6047a982d89SJeremy L. Thompson   @ref Backend
6057a982d89SJeremy L. Thompson **/
606d1d35e2fSjeremylt int CeedSetObjectDelegate(Ceed ceed, Ceed delegate, const char *obj_name) {
607d1d35e2fSjeremylt   CeedInt count = ceed->obj_delegate_count;
6087a982d89SJeremy L. Thompson 
6097a982d89SJeremy L. Thompson   // Malloc or Realloc
6107a982d89SJeremy L. Thompson   if (count) {
6112b730f8bSJeremy L Thompson     CeedCall(CeedRealloc(count + 1, &ceed->obj_delegates));
6127a982d89SJeremy L. Thompson   } else {
6132b730f8bSJeremy L Thompson     CeedCall(CeedCalloc(1, &ceed->obj_delegates));
6147a982d89SJeremy L. Thompson   }
615d1d35e2fSjeremylt   ceed->obj_delegate_count++;
6167a982d89SJeremy L. Thompson 
6177a982d89SJeremy L. Thompson   // Set object delegate
6189bc66399SJeremy L Thompson   CeedCall(CeedReferenceCopy(delegate, &ceed->obj_delegates[count].delegate));
6192b730f8bSJeremy L Thompson   CeedCall(CeedStringAllocCopy(obj_name, &ceed->obj_delegates[count].obj_name));
6207a982d89SJeremy L. Thompson 
6217a982d89SJeremy L. Thompson   // Set delegate parent
6227a982d89SJeremy L. Thompson   delegate->parent = ceed;
623e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6247a982d89SJeremy L. Thompson }
6257a982d89SJeremy L. Thompson 
6267a982d89SJeremy L. Thompson /**
627ca94c3ddSJeremy L Thompson   @brief Get the fallback resource for `CeedOperator`
6287a982d89SJeremy L. Thompson 
629ca94c3ddSJeremy L Thompson   @param[in]  ceed     `Ceed` context
6307a982d89SJeremy L. Thompson   @param[out] resource Variable to store fallback resource
6317a982d89SJeremy L. Thompson 
6327a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6337a982d89SJeremy L. Thompson 
6347a982d89SJeremy L. Thompson   @ref Backend
6357a982d89SJeremy L. Thompson **/
636363aefefSSebastian Grimberg int CeedGetOperatorFallbackResource(Ceed ceed, const char **resource) {
637d1d35e2fSjeremylt   *resource = (const char *)ceed->op_fallback_resource;
638e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6397a982d89SJeremy L. Thompson }
6407a982d89SJeremy L. Thompson 
6417a982d89SJeremy L. Thompson /**
642ca94c3ddSJeremy L Thompson   @brief Get the fallback `Ceed` for `CeedOperator`
6438687e1d4SJeremy L Thompson 
644ca94c3ddSJeremy L Thompson   @param[in]  ceed          `Ceed` context
645ca94c3ddSJeremy L Thompson   @param[out] fallback_ceed Variable to store fallback `Ceed`
6468687e1d4SJeremy L Thompson 
6478687e1d4SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
6488687e1d4SJeremy L Thompson 
6498687e1d4SJeremy L Thompson   @ref Backend
6508687e1d4SJeremy L Thompson **/
6518687e1d4SJeremy L Thompson int CeedGetOperatorFallbackCeed(Ceed ceed, Ceed *fallback_ceed) {
652d04bbc78SJeremy L Thompson   if (ceed->has_valid_op_fallback_resource) {
653*ca38d01dSJeremy L Thompson     CeedDebug256(ceed, CEED_DEBUG_COLOR_SUCCESS, "---------- Ceed Fallback ----------\n");
654*ca38d01dSJeremy L Thompson     CeedDebug(ceed, "Falling back from Ceed with backend %s at address %p to Ceed with backend %s", ceed->resource, ceed, ceed->op_fallback_resource);
655d04bbc78SJeremy L Thompson   }
6568687e1d4SJeremy L Thompson 
657*ca38d01dSJeremy L Thompson   // Create fallback Ceed if uninitialized
658d04bbc78SJeremy L Thompson   if (!ceed->op_fallback_ceed && ceed->has_valid_op_fallback_resource) {
65913f886e9SJeremy L Thompson     CeedDebug(ceed, "Creating fallback Ceed");
660d04bbc78SJeremy L Thompson 
6618687e1d4SJeremy L Thompson     Ceed        fallback_ceed;
662d04bbc78SJeremy L Thompson     const char *fallback_resource;
663d04bbc78SJeremy L Thompson 
664363aefefSSebastian Grimberg     CeedCall(CeedGetOperatorFallbackResource(ceed, &fallback_resource));
6652b730f8bSJeremy L Thompson     CeedCall(CeedInit(fallback_resource, &fallback_ceed));
6668687e1d4SJeremy L Thompson     fallback_ceed->op_fallback_parent = ceed;
6678687e1d4SJeremy L Thompson     fallback_ceed->Error              = ceed->Error;
6688687e1d4SJeremy L Thompson     ceed->op_fallback_ceed            = fallback_ceed;
669b13efd58SJeremy L Thompson     {
670aeb3a72dSJeremy L Thompson       const char **jit_source_roots;
671aeb3a72dSJeremy L Thompson       CeedInt      num_jit_source_roots = 0;
672b13efd58SJeremy L Thompson 
673aeb3a72dSJeremy L Thompson       CeedCall(CeedGetJitSourceRoots(ceed, &num_jit_source_roots, &jit_source_roots));
674aeb3a72dSJeremy L Thompson       for (CeedInt i = 0; i < num_jit_source_roots; i++) {
675aeb3a72dSJeremy L Thompson         CeedCall(CeedAddJitSourceRoot(fallback_ceed, jit_source_roots[i]));
676b13efd58SJeremy L Thompson       }
677aeb3a72dSJeremy L Thompson       CeedCall(CeedRestoreJitSourceRoots(ceed, &jit_source_roots));
678b13efd58SJeremy L Thompson     }
6794753b775SJeremy L Thompson     {
6804753b775SJeremy L Thompson       const char **jit_defines;
6814753b775SJeremy L Thompson       CeedInt      num_jit_defines = 0;
6824753b775SJeremy L Thompson 
6834753b775SJeremy L Thompson       CeedCall(CeedGetJitDefines(ceed, &num_jit_defines, &jit_defines));
6844753b775SJeremy L Thompson       for (CeedInt i = 0; i < num_jit_defines; i++) {
6854753b775SJeremy L Thompson         CeedCall(CeedAddJitSourceRoot(fallback_ceed, jit_defines[i]));
6864753b775SJeremy L Thompson       }
6874753b775SJeremy L Thompson       CeedCall(CeedRestoreJitDefines(ceed, &jit_defines));
6884753b775SJeremy L Thompson     }
6898687e1d4SJeremy L Thompson   }
6909bc66399SJeremy L Thompson   *fallback_ceed = NULL;
691*ca38d01dSJeremy L Thompson   CeedDebug(ceed, "Fallback Ceed with backend %s at address %p\n", ceed->op_fallback_resource, ceed->op_fallback_ceed);
6929bc66399SJeremy L Thompson   if (ceed->op_fallback_ceed) CeedCall(CeedReferenceCopy(ceed->op_fallback_ceed, fallback_ceed));
6938687e1d4SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6948687e1d4SJeremy L Thompson }
6958687e1d4SJeremy L Thompson 
6968687e1d4SJeremy L Thompson /**
697ca94c3ddSJeremy L Thompson   @brief Set the fallback resource for `CeedOperator`.
6984385fb7fSSebastian Grimberg 
699ea61e9acSJeremy L Thompson   The current resource, if any, is freed by calling this function.
700ca94c3ddSJeremy L Thompson   This string is freed upon the destruction of the `Ceed` context.
7017a982d89SJeremy L. Thompson 
702ca94c3ddSJeremy L Thompson   @param[in,out] ceed     `Ceed` context
703ea61e9acSJeremy L Thompson   @param[in]     resource Fallback resource to set
7047a982d89SJeremy L. Thompson 
7057a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7067a982d89SJeremy L. Thompson 
7077a982d89SJeremy L. Thompson   @ref Backend
7087a982d89SJeremy L. Thompson **/
7097a982d89SJeremy L. Thompson int CeedSetOperatorFallbackResource(Ceed ceed, const char *resource) {
7107a982d89SJeremy L. Thompson   // Free old
7112b730f8bSJeremy L Thompson   CeedCall(CeedFree(&ceed->op_fallback_resource));
7127a982d89SJeremy L. Thompson 
7137a982d89SJeremy L. Thompson   // Set new
7142b730f8bSJeremy L Thompson   CeedCall(CeedStringAllocCopy(resource, (char **)&ceed->op_fallback_resource));
715d04bbc78SJeremy L Thompson 
716d04bbc78SJeremy L Thompson   // Check validity
7172b730f8bSJeremy L Thompson   ceed->has_valid_op_fallback_resource = ceed->op_fallback_resource && ceed->resource && strcmp(ceed->op_fallback_resource, ceed->resource);
718e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7197a982d89SJeremy L. Thompson }
7207a982d89SJeremy L. Thompson 
7217a982d89SJeremy L. Thompson /**
722ca94c3ddSJeremy L Thompson   @brief Flag `Ceed` context as deterministic
7239525855cSJeremy L Thompson 
724ca94c3ddSJeremy L Thompson   @param[in]  ceed             `Ceed` to flag as deterministic
72596b902e2Sjeremylt   @param[out] is_deterministic Deterministic status to set
7269525855cSJeremy L Thompson 
7279525855cSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
7289525855cSJeremy L Thompson 
7299525855cSJeremy L Thompson   @ref Backend
7309525855cSJeremy L Thompson **/
731d1d35e2fSjeremylt int CeedSetDeterministic(Ceed ceed, bool is_deterministic) {
732d1d35e2fSjeremylt   ceed->is_deterministic = is_deterministic;
733e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7349525855cSJeremy L Thompson }
7359525855cSJeremy L Thompson 
7369525855cSJeremy L Thompson /**
737ca94c3ddSJeremy L Thompson   @brief Set a backend function.
7387a982d89SJeremy L. Thompson 
739ea61e9acSJeremy L Thompson   This function is used for a backend to set the function associated with the Ceed objects.
740ca94c3ddSJeremy 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().
7419fd66db6SSebastian Grimberg   Note, the prefix 'Ceed' is not required for the object type ("Basis" vs "CeedBasis").
7427a982d89SJeremy L. Thompson 
743ca94c3ddSJeremy L Thompson   @param[in]  ceed      `Ceed` context for error handling
744ea61e9acSJeremy L Thompson   @param[in]  type      Type of Ceed object to set function for
7457a982d89SJeremy L. Thompson   @param[out] object    Ceed object to set function for
746ea61e9acSJeremy L Thompson   @param[in]  func_name Name of function to set
747ea61e9acSJeremy L Thompson   @param[in]  f         Function to set
7487a982d89SJeremy L. Thompson 
7497a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7507a982d89SJeremy L. Thompson 
7517a982d89SJeremy L. Thompson   @ref Backend
7527a982d89SJeremy L. Thompson **/
753897d4737SSebastian Grimberg int CeedSetBackendFunctionImpl(Ceed ceed, const char *type, void *object, const char *func_name, void (*f)(void)) {
754d1d35e2fSjeremylt   char lookup_name[CEED_MAX_RESOURCE_LEN + 1] = "";
7557a982d89SJeremy L. Thompson 
7567a982d89SJeremy L. Thompson   // Build lookup name
7572b730f8bSJeremy L Thompson   if (strcmp(type, "Ceed")) strncat(lookup_name, "Ceed", CEED_MAX_RESOURCE_LEN);
758d1d35e2fSjeremylt   strncat(lookup_name, type, CEED_MAX_RESOURCE_LEN);
759d1d35e2fSjeremylt   strncat(lookup_name, func_name, CEED_MAX_RESOURCE_LEN);
7607a982d89SJeremy L. Thompson 
7617a982d89SJeremy L. Thompson   // Find and use offset
7622b730f8bSJeremy L Thompson   for (CeedInt i = 0; ceed->f_offsets[i].func_name; i++) {
763d1d35e2fSjeremylt     if (!strcmp(ceed->f_offsets[i].func_name, lookup_name)) {
764d1d35e2fSjeremylt       size_t offset          = ceed->f_offsets[i].offset;
7657a982d89SJeremy L. Thompson       int (**fpointer)(void) = (int (**)(void))((char *)object + offset);  // *NOPAD*
7661c66c397SJeremy L Thompson 
767897d4737SSebastian Grimberg       *fpointer = (int (*)(void))f;
768e15f9bd0SJeremy L Thompson       return CEED_ERROR_SUCCESS;
7697a982d89SJeremy L. Thompson     }
7702b730f8bSJeremy L Thompson   }
7717a982d89SJeremy L. Thompson 
7727a982d89SJeremy L. Thompson   // LCOV_EXCL_START
7732b730f8bSJeremy L Thompson   return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Requested function '%s' was not found for CEED object '%s'", func_name, type);
7747a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
7757a982d89SJeremy L. Thompson }
7767a982d89SJeremy L. Thompson 
7777a982d89SJeremy L. Thompson /**
778ca94c3ddSJeremy L Thompson   @brief Retrieve backend data for a `Ceed` context
7797a982d89SJeremy L. Thompson 
780ca94c3ddSJeremy L Thompson   @param[in]  ceed `Ceed` context to retrieve data of
7817a982d89SJeremy L. Thompson   @param[out] data Address to save data to
7827a982d89SJeremy L. Thompson 
7837a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7847a982d89SJeremy L. Thompson 
7857a982d89SJeremy L. Thompson   @ref Backend
7867a982d89SJeremy L. Thompson **/
787777ff853SJeremy L Thompson int CeedGetData(Ceed ceed, void *data) {
788777ff853SJeremy L Thompson   *(void **)data = ceed->data;
789e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7907a982d89SJeremy L. Thompson }
7917a982d89SJeremy L. Thompson 
7927a982d89SJeremy L. Thompson /**
793ca94c3ddSJeremy L Thompson   @brief Set backend data for a `Ceed` context
7947a982d89SJeremy L. Thompson 
795ca94c3ddSJeremy L Thompson   @param[in,out] ceed `Ceed` context to set data of
796ea61e9acSJeremy L Thompson   @param[in]     data Address of data to set
7977a982d89SJeremy L. Thompson 
7987a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7997a982d89SJeremy L. Thompson 
8007a982d89SJeremy L. Thompson   @ref Backend
8017a982d89SJeremy L. Thompson **/
802777ff853SJeremy L Thompson int CeedSetData(Ceed ceed, void *data) {
803777ff853SJeremy L Thompson   ceed->data = data;
804e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
8057a982d89SJeremy L. Thompson }
8067a982d89SJeremy L. Thompson 
80734359f16Sjeremylt /**
808ca94c3ddSJeremy L Thompson   @brief Increment the reference counter for a `Ceed` context
80934359f16Sjeremylt 
810ca94c3ddSJeremy L Thompson   @param[in,out] ceed `Ceed` context to increment the reference counter
81134359f16Sjeremylt 
81234359f16Sjeremylt   @return An error code: 0 - success, otherwise - failure
81334359f16Sjeremylt 
81434359f16Sjeremylt   @ref Backend
81534359f16Sjeremylt **/
8169560d06aSjeremylt int CeedReference(Ceed ceed) {
81734359f16Sjeremylt   ceed->ref_count++;
81834359f16Sjeremylt   return CEED_ERROR_SUCCESS;
81934359f16Sjeremylt }
82034359f16Sjeremylt 
82173501bfeSJeremy L Thompson /**
8220b37c066SZach Atkins   @brief Computes the current memory usage of the work vectors in a `Ceed` context and prints to debug.abort
8230b37c066SZach Atkins 
8240b37c066SZach Atkins   @param[in]  ceed     `Ceed` context
825ec4241e6SJeremy L Thompson   @param[out] usage_mb Address of the variable where the MB of work vector usage will be stored
8260b37c066SZach Atkins 
8270b37c066SZach Atkins   @return An error code: 0 - success, otherwise - failure
8280b37c066SZach Atkins 
8290b37c066SZach Atkins   @ref Developer
8300b37c066SZach Atkins **/
83155326fe7SZach Atkins int CeedGetWorkVectorMemoryUsage(Ceed ceed, CeedScalar *usage_mb) {
832fd326ce8SZach Atkins   if (!ceed->VectorCreate) {
833fd326ce8SZach Atkins     Ceed delegate;
834fd326ce8SZach Atkins 
835fd326ce8SZach Atkins     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Vector"));
836fd326ce8SZach Atkins     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement VectorCreate");
837fd326ce8SZach Atkins     CeedCall(CeedGetWorkVectorMemoryUsage(delegate, usage_mb));
838fd326ce8SZach Atkins     CeedCall(CeedDestroy(&delegate));
839fd326ce8SZach Atkins     return CEED_ERROR_SUCCESS;
840fd326ce8SZach Atkins   }
84155326fe7SZach Atkins   *usage_mb = 0.0;
8420b37c066SZach Atkins   if (ceed->work_vectors) {
8430b37c066SZach Atkins     for (CeedInt i = 0; i < ceed->work_vectors->num_vecs; i++) {
8440b37c066SZach Atkins       CeedSize vec_len;
8450b37c066SZach Atkins       CeedCall(CeedVectorGetLength(ceed->work_vectors->vecs[i], &vec_len));
84655326fe7SZach Atkins       *usage_mb += vec_len;
8470b37c066SZach Atkins     }
84855326fe7SZach Atkins     *usage_mb *= sizeof(CeedScalar) * 1e-6;
84955326fe7SZach Atkins     CeedDebug(ceed, "Resource {%s}: Work vectors memory usage: %" CeedInt_FMT " vectors, %g MB\n", ceed->resource, ceed->work_vectors->num_vecs,
85055326fe7SZach Atkins               *usage_mb);
8510b37c066SZach Atkins   }
8520b37c066SZach Atkins   return CEED_ERROR_SUCCESS;
8530b37c066SZach Atkins }
8540b37c066SZach Atkins 
8550b37c066SZach Atkins /**
8560b37c066SZach Atkins   @brief Clear inactive work vectors in a `Ceed` context below a minimum length.
8570b37c066SZach Atkins 
8580b37c066SZach Atkins   @param[in,out] ceed    `Ceed` context
8590b37c066SZach Atkins   @param[in]     min_len Minimum length of work vector to keep
8600b37c066SZach Atkins 
8610b37c066SZach Atkins   @return An error code: 0 - success, otherwise - failure
8620b37c066SZach Atkins 
8630b37c066SZach Atkins   @ref Backend
8640b37c066SZach Atkins **/
8650b37c066SZach Atkins int CeedClearWorkVectors(Ceed ceed, CeedSize min_len) {
866fd326ce8SZach Atkins   if (!ceed->VectorCreate) {
867fd326ce8SZach Atkins     Ceed delegate;
868fd326ce8SZach Atkins 
869fd326ce8SZach Atkins     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Vector"));
870fd326ce8SZach Atkins     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement VectorCreate");
871fd326ce8SZach Atkins     CeedCall(CeedClearWorkVectors(delegate, min_len));
872fd326ce8SZach Atkins     CeedCall(CeedDestroy(&delegate));
873fd326ce8SZach Atkins     return CEED_ERROR_SUCCESS;
874fd326ce8SZach Atkins   }
8750b37c066SZach Atkins   if (!ceed->work_vectors) return CEED_ERROR_SUCCESS;
8760b37c066SZach Atkins   for (CeedInt i = 0; i < ceed->work_vectors->num_vecs; i++) {
8770b37c066SZach Atkins     if (ceed->work_vectors->is_in_use[i]) continue;
8780b37c066SZach Atkins     CeedSize vec_len;
8790b37c066SZach Atkins     CeedCall(CeedVectorGetLength(ceed->work_vectors->vecs[i], &vec_len));
8800b37c066SZach Atkins     if (vec_len < min_len) {
88156a26733SZach Atkins       ceed->ref_count += 2;  // Note: increase ref_count to prevent Ceed destructor from triggering
8820b37c066SZach Atkins       CeedCall(CeedVectorDestroy(&ceed->work_vectors->vecs[i]));
8830b37c066SZach Atkins       ceed->ref_count -= 1;  // Note: restore ref_count
8840b37c066SZach Atkins       ceed->work_vectors->num_vecs--;
8850b37c066SZach Atkins       if (ceed->work_vectors->num_vecs > 0) {
8860b37c066SZach Atkins         ceed->work_vectors->vecs[i]                                 = ceed->work_vectors->vecs[ceed->work_vectors->num_vecs];
8870b37c066SZach Atkins         ceed->work_vectors->is_in_use[i]                            = ceed->work_vectors->is_in_use[ceed->work_vectors->num_vecs];
8880b37c066SZach Atkins         ceed->work_vectors->is_in_use[ceed->work_vectors->num_vecs] = false;
8890b37c066SZach Atkins         i--;
8900b37c066SZach Atkins       }
8910b37c066SZach Atkins     }
8920b37c066SZach Atkins   }
8930b37c066SZach Atkins   return CEED_ERROR_SUCCESS;
8940b37c066SZach Atkins }
8950b37c066SZach Atkins 
8960b37c066SZach Atkins /**
89773501bfeSJeremy L Thompson   @brief Get a `CeedVector` for scratch work from a `Ceed` context.
89873501bfeSJeremy L Thompson 
89973501bfeSJeremy L Thompson   Note: This vector must be restored with @ref CeedRestoreWorkVector().
90073501bfeSJeremy L Thompson 
90173501bfeSJeremy L Thompson   @param[in]  ceed `Ceed` context
90273501bfeSJeremy L Thompson   @param[in]  len  Minimum length of work vector
90373501bfeSJeremy L Thompson   @param[out] vec  Address of the variable where `CeedVector` will be stored
90473501bfeSJeremy L Thompson 
90573501bfeSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
90673501bfeSJeremy L Thompson 
90773501bfeSJeremy L Thompson   @ref Backend
90873501bfeSJeremy L Thompson **/
90973501bfeSJeremy L Thompson int CeedGetWorkVector(Ceed ceed, CeedSize len, CeedVector *vec) {
91073501bfeSJeremy L Thompson   CeedInt    i = 0;
91155326fe7SZach Atkins   CeedScalar usage_mb;
91273501bfeSJeremy L Thompson 
913fd326ce8SZach Atkins   if (!ceed->VectorCreate) {
914fd326ce8SZach Atkins     Ceed delegate;
915fd326ce8SZach Atkins 
916fd326ce8SZach Atkins     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Vector"));
917fd326ce8SZach Atkins     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement VectorCreate");
918fd326ce8SZach Atkins     CeedCall(CeedGetWorkVector(delegate, len, vec));
919fd326ce8SZach Atkins     CeedCall(CeedDestroy(&delegate));
920fd326ce8SZach Atkins     return CEED_ERROR_SUCCESS;
921fd326ce8SZach Atkins   }
922fd326ce8SZach Atkins 
92373501bfeSJeremy L Thompson   if (!ceed->work_vectors) CeedCall(CeedWorkVectorsCreate(ceed));
92473501bfeSJeremy L Thompson 
92573501bfeSJeremy L Thompson   // Search for big enough work vector
92673501bfeSJeremy L Thompson   for (i = 0; i < ceed->work_vectors->num_vecs; i++) {
92773501bfeSJeremy L Thompson     if (!ceed->work_vectors->is_in_use[i]) {
92873501bfeSJeremy L Thompson       CeedSize work_len;
92973501bfeSJeremy L Thompson 
93073501bfeSJeremy L Thompson       CeedCall(CeedVectorGetLength(ceed->work_vectors->vecs[i], &work_len));
93173501bfeSJeremy L Thompson       if (work_len >= len) break;
93273501bfeSJeremy L Thompson     }
93373501bfeSJeremy L Thompson   }
93473501bfeSJeremy L Thompson   // Long enough vector was not found
93573501bfeSJeremy L Thompson   if (i == ceed->work_vectors->num_vecs) {
93673501bfeSJeremy L Thompson     if (ceed->work_vectors->max_vecs == 0) {
93773501bfeSJeremy L Thompson       ceed->work_vectors->max_vecs = 1;
93873501bfeSJeremy L Thompson       CeedCall(CeedCalloc(ceed->work_vectors->max_vecs, &ceed->work_vectors->vecs));
93973501bfeSJeremy L Thompson       CeedCall(CeedCalloc(ceed->work_vectors->max_vecs, &ceed->work_vectors->is_in_use));
94073501bfeSJeremy L Thompson     } else if (ceed->work_vectors->max_vecs == i) {
94173501bfeSJeremy L Thompson       ceed->work_vectors->max_vecs *= 2;
94273501bfeSJeremy L Thompson       CeedCall(CeedRealloc(ceed->work_vectors->max_vecs, &ceed->work_vectors->vecs));
94373501bfeSJeremy L Thompson       CeedCall(CeedRealloc(ceed->work_vectors->max_vecs, &ceed->work_vectors->is_in_use));
94473501bfeSJeremy L Thompson     }
94573501bfeSJeremy L Thompson     ceed->work_vectors->num_vecs++;
94673501bfeSJeremy L Thompson     CeedCallBackend(CeedVectorCreate(ceed, len, &ceed->work_vectors->vecs[i]));
94773501bfeSJeremy L Thompson     ceed->ref_count--;  // Note: ref_count manipulation to prevent a ref-loop
94855326fe7SZach Atkins     if (ceed->is_debug) CeedGetWorkVectorMemoryUsage(ceed, &usage_mb);
94973501bfeSJeremy L Thompson   }
95073501bfeSJeremy L Thompson   // Return pointer to work vector
95173501bfeSJeremy L Thompson   ceed->work_vectors->is_in_use[i] = true;
95273501bfeSJeremy L Thompson   *vec                             = NULL;
95373501bfeSJeremy L Thompson   CeedCall(CeedVectorReferenceCopy(ceed->work_vectors->vecs[i], vec));
95473501bfeSJeremy L Thompson   ceed->ref_count++;  // Note: bump ref_count to account for external access
95573501bfeSJeremy L Thompson   return CEED_ERROR_SUCCESS;
95673501bfeSJeremy L Thompson }
95773501bfeSJeremy L Thompson 
95873501bfeSJeremy L Thompson /**
95973501bfeSJeremy L Thompson   @brief Restore a `CeedVector` for scratch work from a `Ceed` context from @ref CeedGetWorkVector()
96073501bfeSJeremy L Thompson 
96173501bfeSJeremy L Thompson   @param[in]  ceed `Ceed` context
96273501bfeSJeremy L Thompson   @param[out] vec  `CeedVector` to restore
96373501bfeSJeremy L Thompson 
96473501bfeSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
96573501bfeSJeremy L Thompson 
96673501bfeSJeremy L Thompson   @ref Backend
96773501bfeSJeremy L Thompson **/
96873501bfeSJeremy L Thompson int CeedRestoreWorkVector(Ceed ceed, CeedVector *vec) {
969fd326ce8SZach Atkins   if (!ceed->VectorCreate) {
970fd326ce8SZach Atkins     Ceed delegate;
971fd326ce8SZach Atkins 
972fd326ce8SZach Atkins     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Vector"));
973fd326ce8SZach Atkins     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement VectorCreate");
974fd326ce8SZach Atkins     CeedCall(CeedRestoreWorkVector(delegate, vec));
975fd326ce8SZach Atkins     CeedCall(CeedDestroy(&delegate));
976fd326ce8SZach Atkins     return CEED_ERROR_SUCCESS;
977fd326ce8SZach Atkins   }
978fd326ce8SZach Atkins 
97973501bfeSJeremy L Thompson   for (CeedInt i = 0; i < ceed->work_vectors->num_vecs; i++) {
98073501bfeSJeremy L Thompson     if (*vec == ceed->work_vectors->vecs[i]) {
98173501bfeSJeremy 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");
98273501bfeSJeremy L Thompson       CeedCall(CeedVectorDestroy(vec));
98373501bfeSJeremy L Thompson       ceed->work_vectors->is_in_use[i] = false;
98473501bfeSJeremy L Thompson       ceed->ref_count--;  // Note: reduce ref_count again to prevent a ref-loop
98573501bfeSJeremy L Thompson       return CEED_ERROR_SUCCESS;
98673501bfeSJeremy L Thompson     }
98773501bfeSJeremy L Thompson   }
98873501bfeSJeremy L Thompson   // LCOV_EXCL_START
98973501bfeSJeremy L Thompson   return CeedError(ceed, CEED_ERROR_MAJOR, "vec was not checked out via CeedGetWorkVector()");
99073501bfeSJeremy L Thompson   // LCOV_EXCL_STOP
99173501bfeSJeremy L Thompson }
99273501bfeSJeremy L Thompson 
993b13efd58SJeremy L Thompson /**
994b13efd58SJeremy L Thompson   @brief Retrieve list of additional JiT source roots from `Ceed` context.
995b13efd58SJeremy L Thompson 
996b13efd58SJeremy L Thompson   Note: The caller is responsible for restoring `jit_source_roots` with @ref CeedRestoreJitSourceRoots().
997b13efd58SJeremy L Thompson 
998b13efd58SJeremy L Thompson   @param[in]  ceed             `Ceed` context
999b13efd58SJeremy L Thompson   @param[out] num_source_roots Number of JiT source directories
1000b13efd58SJeremy L Thompson   @param[out] jit_source_roots Absolute paths to additional JiT source directories
1001b13efd58SJeremy L Thompson 
1002b13efd58SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1003b13efd58SJeremy L Thompson 
1004b13efd58SJeremy L Thompson   @ref Backend
1005b13efd58SJeremy L Thompson **/
1006b13efd58SJeremy L Thompson int CeedGetJitSourceRoots(Ceed ceed, CeedInt *num_source_roots, const char ***jit_source_roots) {
1007b13efd58SJeremy L Thompson   Ceed ceed_parent;
1008b13efd58SJeremy L Thompson 
1009b13efd58SJeremy L Thompson   CeedCall(CeedGetParent(ceed, &ceed_parent));
1010b13efd58SJeremy L Thompson   *num_source_roots = ceed_parent->num_jit_source_roots;
1011b13efd58SJeremy L Thompson   *jit_source_roots = (const char **)ceed_parent->jit_source_roots;
1012aeb3a72dSJeremy L Thompson   ceed_parent->num_jit_source_roots_readers++;
10139bc66399SJeremy L Thompson   CeedCall(CeedDestroy(&ceed_parent));
1014b13efd58SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1015b13efd58SJeremy L Thompson }
1016b13efd58SJeremy L Thompson 
1017b13efd58SJeremy L Thompson /**
1018b13efd58SJeremy L Thompson   @brief Restore list of additional JiT source roots from with @ref CeedGetJitSourceRoots()
1019b13efd58SJeremy L Thompson 
1020b13efd58SJeremy L Thompson   @param[in]  ceed             `Ceed` context
1021b13efd58SJeremy L Thompson   @param[out] jit_source_roots Absolute paths to additional JiT source directories
1022b13efd58SJeremy L Thompson 
1023b13efd58SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1024b13efd58SJeremy L Thompson 
1025b13efd58SJeremy L Thompson   @ref Backend
1026b13efd58SJeremy L Thompson **/
1027b13efd58SJeremy L Thompson int CeedRestoreJitSourceRoots(Ceed ceed, const char ***jit_source_roots) {
1028aeb3a72dSJeremy L Thompson   Ceed ceed_parent;
1029aeb3a72dSJeremy L Thompson 
1030aeb3a72dSJeremy L Thompson   CeedCall(CeedGetParent(ceed, &ceed_parent));
1031b13efd58SJeremy L Thompson   *jit_source_roots = NULL;
1032aeb3a72dSJeremy L Thompson   ceed_parent->num_jit_source_roots_readers--;
10339bc66399SJeremy L Thompson   CeedCall(CeedDestroy(&ceed_parent));
1034b13efd58SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1035b13efd58SJeremy L Thompson }
1036b13efd58SJeremy L Thompson 
10374753b775SJeremy L Thompson /**
10384753b775SJeremy L Thompson   @brief Retrieve list of additional JiT defines from `Ceed` context.
10394753b775SJeremy L Thompson 
10404753b775SJeremy L Thompson   Note: The caller is responsible for restoring `jit_defines` with @ref CeedRestoreJitDefines().
10414753b775SJeremy L Thompson 
10424753b775SJeremy L Thompson   @param[in]  ceed            `Ceed` context
10434753b775SJeremy L Thompson   @param[out] num_jit_defines Number of JiT defines
10444753b775SJeremy L Thompson   @param[out] jit_defines     Strings such as `foo=bar`, used as `-Dfoo=bar` in JiT
10454753b775SJeremy L Thompson 
10464753b775SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
10474753b775SJeremy L Thompson 
10484753b775SJeremy L Thompson   @ref Backend
10494753b775SJeremy L Thompson **/
10502686ebe6SJed Brown int CeedGetJitDefines(Ceed ceed, CeedInt *num_jit_defines, const char ***jit_defines) {
10514753b775SJeremy L Thompson   Ceed ceed_parent;
10524753b775SJeremy L Thompson 
10534753b775SJeremy L Thompson   CeedCall(CeedGetParent(ceed, &ceed_parent));
10542686ebe6SJed Brown   *num_jit_defines = ceed_parent->num_jit_defines;
10554753b775SJeremy L Thompson   *jit_defines     = (const char **)ceed_parent->jit_defines;
1056aeb3a72dSJeremy L Thompson   ceed_parent->num_jit_defines_readers++;
10579bc66399SJeremy L Thompson   CeedCall(CeedDestroy(&ceed_parent));
10584753b775SJeremy L Thompson   return CEED_ERROR_SUCCESS;
10594753b775SJeremy L Thompson }
10604753b775SJeremy L Thompson 
10614753b775SJeremy L Thompson /**
10624753b775SJeremy L Thompson   @brief Restore list of additional JiT defines from with @ref CeedGetJitDefines()
10634753b775SJeremy L Thompson 
10644753b775SJeremy L Thompson   @param[in]  ceed        `Ceed` context
10654753b775SJeremy L Thompson   @param[out] jit_defines String such as `foo=bar`, used as `-Dfoo=bar` in JiT
10664753b775SJeremy L Thompson 
10674753b775SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
10684753b775SJeremy L Thompson 
10694753b775SJeremy L Thompson   @ref Backend
10704753b775SJeremy L Thompson **/
10714753b775SJeremy L Thompson int CeedRestoreJitDefines(Ceed ceed, const char ***jit_defines) {
1072aeb3a72dSJeremy L Thompson   Ceed ceed_parent;
1073aeb3a72dSJeremy L Thompson 
1074aeb3a72dSJeremy L Thompson   CeedCall(CeedGetParent(ceed, &ceed_parent));
10754753b775SJeremy L Thompson   *jit_defines = NULL;
1076aeb3a72dSJeremy L Thompson   ceed_parent->num_jit_defines_readers--;
10779bc66399SJeremy L Thompson   CeedCall(CeedDestroy(&ceed_parent));
10784753b775SJeremy L Thompson   return CEED_ERROR_SUCCESS;
10794753b775SJeremy L Thompson }
10804753b775SJeremy L Thompson 
10817a982d89SJeremy L. Thompson /// @}
10827a982d89SJeremy L. Thompson 
10837a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
10847a982d89SJeremy L. Thompson /// Ceed Public API
10857a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
10867a982d89SJeremy L. Thompson /// @addtogroup CeedUser
10877a982d89SJeremy L. Thompson /// @{
10887a982d89SJeremy L. Thompson 
10897a982d89SJeremy L. Thompson /**
1090ca94c3ddSJeremy L Thompson   @brief Get the list of available resource names for `Ceed` contexts
10914385fb7fSSebastian Grimberg 
1092ca94c3ddSJeremy 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.
109322e44211Sjeremylt 
109492ee7d1cSjeremylt   @param[out] n          Number of available resources
109592ee7d1cSjeremylt   @param[out] resources  List of available resource names
109622e44211Sjeremylt   @param[out] priorities Resource name prioritization values, lower is better
109722e44211Sjeremylt 
109822e44211Sjeremylt   @return An error code: 0 - success, otherwise - failure
109922e44211Sjeremylt 
110022e44211Sjeremylt   @ref User
110122e44211Sjeremylt **/
110222e44211Sjeremylt // LCOV_EXCL_START
11032b730f8bSJeremy L Thompson int CeedRegistryGetList(size_t *n, char ***const resources, CeedInt **priorities) {
1104d0c91ce9Sjeremylt   *n         = 0;
11059ff86846Sjeremylt   *resources = malloc(num_backends * sizeof(**resources));
11066574a04fSJeremy L Thompson   CeedCheck(resources, NULL, CEED_ERROR_MAJOR, "malloc() failure");
11079ff86846Sjeremylt   if (priorities) {
11089ff86846Sjeremylt     *priorities = malloc(num_backends * sizeof(**priorities));
11096574a04fSJeremy L Thompson     CeedCheck(priorities, NULL, CEED_ERROR_MAJOR, "malloc() failure");
11109ff86846Sjeremylt   }
111122e44211Sjeremylt   for (size_t i = 0; i < num_backends; i++) {
1112d0c91ce9Sjeremylt     // Only report compiled backends
1113d0c91ce9Sjeremylt     if (backends[i].priority < CEED_MAX_BACKEND_PRIORITY) {
111422e44211Sjeremylt       *resources[i] = backends[i].prefix;
11159ff86846Sjeremylt       if (priorities) *priorities[i] = backends[i].priority;
1116d0c91ce9Sjeremylt       *n += 1;
1117d0c91ce9Sjeremylt     }
1118d0c91ce9Sjeremylt   }
11196574a04fSJeremy L Thompson   CeedCheck(*n, NULL, CEED_ERROR_MAJOR, "No backends installed");
1120d0c91ce9Sjeremylt   *resources = realloc(*resources, *n * sizeof(**resources));
11216574a04fSJeremy L Thompson   CeedCheck(resources, NULL, CEED_ERROR_MAJOR, "realloc() failure");
1122d0c91ce9Sjeremylt   if (priorities) {
1123d0c91ce9Sjeremylt     *priorities = realloc(*priorities, *n * sizeof(**priorities));
11246574a04fSJeremy L Thompson     CeedCheck(priorities, NULL, CEED_ERROR_MAJOR, "realloc() failure");
112522e44211Sjeremylt   }
112622e44211Sjeremylt   return CEED_ERROR_SUCCESS;
112745f1e315Sjeremylt }
112822e44211Sjeremylt // LCOV_EXCL_STOP
112922e44211Sjeremylt 
113022e44211Sjeremylt /**
1131ca94c3ddSJeremy L Thompson   @brief Initialize a `Ceed` context to use the specified resource.
11324385fb7fSSebastian Grimberg 
1133ca94c3ddSJeremy 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`.
1134b11c1e72Sjeremylt 
1135ea61e9acSJeremy L Thompson   @param[in]  resource Resource to use, e.g., "/cpu/self"
1136ea61e9acSJeremy L Thompson   @param[out] ceed     The library context
1137b11c1e72Sjeremylt 
1138b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1139dfdf5a53Sjeremylt 
11407a982d89SJeremy L. Thompson   @ref User
1141ca94c3ddSJeremy L Thompson 
1142ca94c3ddSJeremy L Thompson   @sa CeedRegister() CeedDestroy()
1143b11c1e72Sjeremylt **/
1144d7b241e6Sjeremylt int CeedInit(const char *resource, Ceed *ceed) {
11452b730f8bSJeremy L Thompson   size_t match_len = 0, match_index = UINT_MAX, match_priority = CEED_MAX_BACKEND_PRIORITY, priority;
1146d7b241e6Sjeremylt 
1147fe2413ffSjeremylt   // Find matching backend
11486574a04fSJeremy L Thompson   CeedCheck(resource, NULL, CEED_ERROR_MAJOR, "No resource provided");
11492b730f8bSJeremy L Thompson   CeedCall(CeedRegisterAll());
115013873f79Sjeremylt 
115122e44211Sjeremylt   // Check for help request
115222e44211Sjeremylt   const char *help_prefix = "help";
11532b730f8bSJeremy L Thompson   size_t      match_help  = 0;
11542b730f8bSJeremy L Thompson   while (match_help < 4 && resource[match_help] == help_prefix[match_help]) match_help++;
115522e44211Sjeremylt   if (match_help == 4) {
11562b730f8bSJeremy L Thompson     fprintf(stderr, "libCEED version: %d.%d%d%s\n", CEED_VERSION_MAJOR, CEED_VERSION_MINOR, CEED_VERSION_PATCH,
115722e44211Sjeremylt             CEED_VERSION_RELEASE ? "" : "+development");
115892ee7d1cSjeremylt     fprintf(stderr, "Available backend resources:\n");
115922e44211Sjeremylt     for (size_t i = 0; i < num_backends; i++) {
1160d0c91ce9Sjeremylt       // Only report compiled backends
11612b730f8bSJeremy L Thompson       if (backends[i].priority < CEED_MAX_BACKEND_PRIORITY) fprintf(stderr, "  %s\n", backends[i].prefix);
116222e44211Sjeremylt     }
116322e44211Sjeremylt     fflush(stderr);
116422e44211Sjeremylt     match_help = 5;  // Delineating character expected
116522e44211Sjeremylt   } else {
116622e44211Sjeremylt     match_help = 0;
116722e44211Sjeremylt   }
116822e44211Sjeremylt 
1169ea61e9acSJeremy L Thompson   // Find best match, computed as number of matching characters from requested resource stem
11702b730f8bSJeremy L Thompson   size_t stem_length = 0;
11712b730f8bSJeremy L Thompson   while (resource[stem_length + match_help] && resource[stem_length + match_help] != ':') stem_length++;
1172d7b241e6Sjeremylt   for (size_t i = 0; i < num_backends; i++) {
11732b730f8bSJeremy L Thompson     size_t      n      = 0;
1174d7b241e6Sjeremylt     const char *prefix = backends[i].prefix;
11752b730f8bSJeremy L Thompson     while (prefix[n] && prefix[n] == resource[n + match_help]) n++;
1176d7b241e6Sjeremylt     priority = backends[i].priority;
1177d1d35e2fSjeremylt     if (n > match_len || (n == match_len && match_priority > priority)) {
1178d1d35e2fSjeremylt       match_len      = n;
1179d1d35e2fSjeremylt       match_priority = priority;
1180f7e22acaSJeremy L Thompson       match_index    = i;
1181d7b241e6Sjeremylt     }
1182d7b241e6Sjeremylt   }
11839c9a0587SLeila Ghaffari   // Using Levenshtein distance to find closest match
11849c9a0587SLeila Ghaffari   if (match_len <= 1 || match_len != stem_length) {
1185203015caSLeila Ghaffari     // LCOV_EXCL_START
11869c9a0587SLeila Ghaffari     size_t lev_dis   = UINT_MAX;
1187f7e22acaSJeremy L Thompson     size_t lev_index = UINT_MAX, lev_priority = CEED_MAX_BACKEND_PRIORITY;
11889c9a0587SLeila Ghaffari     for (size_t i = 0; i < num_backends; i++) {
11899c9a0587SLeila Ghaffari       const char *prefix        = backends[i].prefix;
11909c9a0587SLeila Ghaffari       size_t      prefix_length = strlen(backends[i].prefix);
11919c9a0587SLeila Ghaffari       size_t      min_len       = (prefix_length < stem_length) ? prefix_length : stem_length;
1192092904ddSLeila Ghaffari       size_t      column[min_len + 1];
1193092904ddSLeila Ghaffari       for (size_t j = 0; j <= min_len; j++) column[j] = j;
11949c9a0587SLeila Ghaffari       for (size_t j = 1; j <= min_len; j++) {
11959c9a0587SLeila Ghaffari         column[0] = j;
11969c9a0587SLeila Ghaffari         for (size_t k = 1, last_diag = j - 1; k <= min_len; k++) {
1197092904ddSLeila Ghaffari           size_t old_diag = column[k];
11989c9a0587SLeila Ghaffari           size_t min_1    = (column[k] < column[k - 1]) ? column[k] + 1 : column[k - 1] + 1;
11999c9a0587SLeila Ghaffari           size_t min_2    = last_diag + (resource[k - 1] == prefix[j - 1] ? 0 : 1);
12009c9a0587SLeila Ghaffari           column[k]       = (min_1 < min_2) ? min_1 : min_2;
12019c9a0587SLeila Ghaffari           last_diag       = old_diag;
12029c9a0587SLeila Ghaffari         }
12039c9a0587SLeila Ghaffari       }
12049c9a0587SLeila Ghaffari       size_t n = column[min_len];
12059c9a0587SLeila Ghaffari       priority = backends[i].priority;
12062b730f8bSJeremy L Thompson       if (n < lev_dis || (n == lev_dis && lev_priority > priority)) {
12079c9a0587SLeila Ghaffari         lev_dis      = n;
12089c9a0587SLeila Ghaffari         lev_priority = priority;
1209f7e22acaSJeremy L Thompson         lev_index    = i;
12109c9a0587SLeila Ghaffari       }
12119c9a0587SLeila Ghaffari     }
1212f7e22acaSJeremy L Thompson     const char *prefix_lev = backends[lev_index].prefix;
12132b730f8bSJeremy L Thompson     size_t      lev_length = 0;
12142b730f8bSJeremy L Thompson     while (prefix_lev[lev_length] && prefix_lev[lev_length] != '\0') lev_length++;
12159c9a0587SLeila Ghaffari     size_t m = (lev_length < stem_length) ? lev_length : stem_length;
12166574a04fSJeremy L Thompson     if (lev_dis + 1 >= m) return CeedError(NULL, CEED_ERROR_MAJOR, "No suitable backend: %s", resource);
12176574a04fSJeremy L Thompson     else return CeedError(NULL, CEED_ERROR_MAJOR, "No suitable backend: %s\nClosest match: %s", resource, backends[lev_index].prefix);
1218203015caSLeila Ghaffari     // LCOV_EXCL_STOP
12199c9a0587SLeila Ghaffari   }
1220fe2413ffSjeremylt 
1221fe2413ffSjeremylt   // Setup Ceed
12222b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, ceed));
12232b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, &(*ceed)->jit_source_roots));
1224bc81ce41Sjeremylt   const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER");
12252b730f8bSJeremy L Thompson   if (!ceed_error_handler) ceed_error_handler = "abort";
12262b730f8bSJeremy L Thompson   if (!strcmp(ceed_error_handler, "exit")) (*ceed)->Error = CeedErrorExit;
12272b730f8bSJeremy L Thompson   else if (!strcmp(ceed_error_handler, "store")) (*ceed)->Error = CeedErrorStore;
12282b730f8bSJeremy L Thompson   else (*ceed)->Error = CeedErrorAbort;
1229d1d35e2fSjeremylt   memcpy((*ceed)->err_msg, "No error message stored", 24);
1230d1d35e2fSjeremylt   (*ceed)->ref_count = 1;
1231d7b241e6Sjeremylt   (*ceed)->data      = NULL;
1232fe2413ffSjeremylt 
1233fe2413ffSjeremylt   // Set lookup table
1234d1d35e2fSjeremylt   FOffset f_offsets[] = {
12356e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, Error),
12365ae360d4SJeremy L Thompson       CEED_FTABLE_ENTRY(Ceed, SetStream),
12376e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, GetPreferredMemType),
12386e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, Destroy),
1239f8902d9eSjeremylt       CEED_FTABLE_ENTRY(Ceed, VectorCreate),
12406e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreate),
12413ac8f562SJeremy L Thompson       CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateAtPoints),
12426e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, ElemRestrictionCreateBlocked),
12436e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, BasisCreateTensorH1),
12446e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, BasisCreateH1),
124550c301a5SRezgar Shakeri       CEED_FTABLE_ENTRY(Ceed, BasisCreateHdiv),
1246c4e3f59bSSebastian Grimberg       CEED_FTABLE_ENTRY(Ceed, BasisCreateHcurl),
12476e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, TensorContractCreate),
12486e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, QFunctionCreate),
1249777ff853SJeremy L Thompson       CEED_FTABLE_ENTRY(Ceed, QFunctionContextCreate),
12506e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, OperatorCreate),
125148acf710SJeremy L Thompson       CEED_FTABLE_ENTRY(Ceed, OperatorCreateAtPoints),
12526e79d475Sjeremylt       CEED_FTABLE_ENTRY(Ceed, CompositeOperatorCreate),
12539c774eddSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, HasValidArray),
12549c774eddSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, HasBorrowedArrayOfType),
12550b8f3c4eSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, CopyStrided),
12566e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, SetArray),
12576a6c615bSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, TakeArray),
12586e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, SetValue),
12590b8f3c4eSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, SetValueStrided),
1260f48ed27dSnbeams       CEED_FTABLE_ENTRY(CeedVector, SyncArray),
12616e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, GetArray),
12626e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, GetArrayRead),
12639c774eddSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, GetArrayWrite),
12646e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, RestoreArray),
12656e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, RestoreArrayRead),
1266547d9b97Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, Norm),
1267e0dd3b27Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, Scale),
12680f7fd0f8Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, AXPY),
12695fb68f37SKaren (Ren) Stengel       CEED_FTABLE_ENTRY(CeedVector, AXPBY),
12700f7fd0f8Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, PointwiseMult),
1271d99fa3c5SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedVector, Reciprocal),
12726e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedVector, Destroy),
12736e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedElemRestriction, Apply),
1274f30b1135SSebastian Grimberg       CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyUnsigned),
12757c1dbaffSSebastian Grimberg       CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyUnoriented),
127605fa913cSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyAtPointsInElement),
12776e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedElemRestriction, ApplyBlock),
1278bd33150aSjeremylt       CEED_FTABLE_ENTRY(CeedElemRestriction, GetOffsets),
127977d1c127SSebastian Grimberg       CEED_FTABLE_ENTRY(CeedElemRestriction, GetOrientations),
128077d1c127SSebastian Grimberg       CEED_FTABLE_ENTRY(CeedElemRestriction, GetCurlOrientations),
128119605835SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedElemRestriction, GetAtPointsElementOffset),
12826e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedElemRestriction, Destroy),
12836e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedBasis, Apply),
1284db2becc9SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedBasis, ApplyAdd),
1285c8c3fa7dSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedBasis, ApplyAtPoints),
1286db2becc9SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedBasis, ApplyAddAtPoints),
12876e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedBasis, Destroy),
12886e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedTensorContract, Apply),
12896e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedTensorContract, Destroy),
12906e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedQFunction, Apply),
12918c84ac63Sjeremylt       CEED_FTABLE_ENTRY(CeedQFunction, SetCUDAUserFunction),
12928c84ac63Sjeremylt       CEED_FTABLE_ENTRY(CeedQFunction, SetHIPUserFunction),
12936e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedQFunction, Destroy),
12949c774eddSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, HasValidData),
12959c774eddSJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, HasBorrowedDataOfType),
1296777ff853SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, SetData),
1297891038deSjeremylt       CEED_FTABLE_ENTRY(CeedQFunctionContext, TakeData),
1298777ff853SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, GetData),
129928bfd0b7SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, GetDataRead),
1300777ff853SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, RestoreData),
130128bfd0b7SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, RestoreDataRead),
13022e64a2b9SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, DataDestroy),
1303777ff853SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedQFunctionContext, Destroy),
130480ac2e43SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunction),
130570a7ffb3SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleQFunctionUpdate),
130680ac2e43SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleDiagonal),
13079e9210b8SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddDiagonal),
130880ac2e43SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssemblePointBlockDiagonal),
13099e9210b8SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleAddPointBlockDiagonal),
1310e2f04181SAndrew T. Barker       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleSymbolic),
1311e2f04181SAndrew T. Barker       CEED_FTABLE_ENTRY(CeedOperator, LinearAssemble),
1312cefa2673SJeremy L Thompson       CEED_FTABLE_ENTRY(CeedOperator, LinearAssembleSingle),
1313713f43c3Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, CreateFDMElementInverse),
13146e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, Apply),
1315250756a7Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, ApplyComposite),
1316cae8b89aSjeremylt       CEED_FTABLE_ENTRY(CeedOperator, ApplyAdd),
1317250756a7Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, ApplyAddComposite),
13186e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, ApplyJacobian),
13196e79d475Sjeremylt       CEED_FTABLE_ENTRY(CeedOperator, Destroy),
13206e79d475Sjeremylt       {NULL, 0}  // End of lookup table - used in SetBackendFunction loop
13211dfeef1dSjeremylt   };
1322fe2413ffSjeremylt 
13232b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(sizeof(f_offsets), &(*ceed)->f_offsets));
1324d1d35e2fSjeremylt   memcpy((*ceed)->f_offsets, f_offsets, sizeof(f_offsets));
1325fe2413ffSjeremylt 
13265107b09fSJeremy L Thompson   // Set fallback for advanced CeedOperator functions
1327ca735530SJeremy L Thompson   const char fallback_resource[] = "";
1328ca735530SJeremy L Thompson   CeedCall(CeedSetOperatorFallbackResource(*ceed, fallback_resource));
13295107b09fSJeremy L Thompson 
133060f9e2d6SJeremy L Thompson   // Record env variables CEED_DEBUG or DBG
13311c66c397SJeremy L Thompson   (*ceed)->is_debug = getenv("CEED_DEBUG") || getenv("DEBUG") || getenv("DBG");
133260f9e2d6SJeremy L Thompson 
133322e44211Sjeremylt   // Copy resource prefix, if backend setup successful
13342b730f8bSJeremy L Thompson   CeedCall(CeedStringAllocCopy(backends[match_index].prefix, (char **)&(*ceed)->resource));
1335ee5a26f2SJeremy L Thompson 
1336ee5a26f2SJeremy L Thompson   // Set default JiT source root
1337ea61e9acSJeremy L Thompson   // Note: there will always be the default root for every Ceed but all additional paths are added to the top-most parent
13382b730f8bSJeremy L Thompson   CeedCall(CeedAddJitSourceRoot(*ceed, (char *)CeedJitSourceRootDefault));
1339ee5a26f2SJeremy L Thompson 
1340d04bbc78SJeremy L Thompson   // Backend specific setup
13412b730f8bSJeremy L Thompson   CeedCall(backends[match_index].init(&resource[match_help], *ceed));
1342e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1343d7b241e6Sjeremylt }
1344d7b241e6Sjeremylt 
1345d7b241e6Sjeremylt /**
1346ca94c3ddSJeremy L Thompson   @brief Set the GPU stream for a `Ceed` context
13475ae360d4SJeremy L Thompson 
1348ca94c3ddSJeremy L Thompson   @param[in,out] ceed   `Ceed` context to set the stream
13495ae360d4SJeremy L Thompson   @param[in]     handle Handle to GPU stream
13505ae360d4SJeremy L Thompson 
13515ae360d4SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
13525ae360d4SJeremy L Thompson 
13535ae360d4SJeremy L Thompson   @ref User
13545ae360d4SJeremy L Thompson **/
13555ae360d4SJeremy L Thompson int CeedSetStream(Ceed ceed, void *handle) {
1356ca94c3ddSJeremy L Thompson   CeedCheck(handle, ceed, CEED_ERROR_INCOMPATIBLE, "Stream handle must be non-NULL");
13579ffb25e0SJames Wright   if (ceed->SetStream) {
13585ae360d4SJeremy L Thompson     CeedCall(ceed->SetStream(ceed, handle));
13599ffb25e0SJames Wright   } else {
13609ffb25e0SJames Wright     Ceed delegate;
13619ffb25e0SJames Wright     CeedCall(CeedGetDelegate(ceed, &delegate));
13625ae360d4SJeremy L Thompson 
136328ce3d2aSJeremy L Thompson     if (delegate) CeedCall(CeedSetStream(delegate, handle));
136428ce3d2aSJeremy L Thompson     else return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support setting stream");
13659bc66399SJeremy L Thompson     CeedCall(CeedDestroy(&delegate));
13669ffb25e0SJames Wright   }
13675ae360d4SJeremy L Thompson   return CEED_ERROR_SUCCESS;
13685ae360d4SJeremy L Thompson }
13695ae360d4SJeremy L Thompson 
13705ae360d4SJeremy L Thompson /**
1371ca94c3ddSJeremy L Thompson   @brief Copy the pointer to a `Ceed` context.
13724385fb7fSSebastian Grimberg 
1373ca94c3ddSJeremy L Thompson   Both pointers should be destroyed with @ref CeedDestroy().
1374512bb800SJeremy L Thompson 
1375ca94c3ddSJeremy 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.
1376ca94c3ddSJeremy L Thompson         This `Ceed` context will be destroyed if `*ceed_copy` is the only reference to this `Ceed` context.
13779560d06aSjeremylt 
1378ca94c3ddSJeremy L Thompson   @param[in]     ceed      `Ceed` context to copy reference to
1379ea61e9acSJeremy L Thompson   @param[in,out] ceed_copy Variable to store copied reference
13809560d06aSjeremylt 
13819560d06aSjeremylt   @return An error code: 0 - success, otherwise - failure
13829560d06aSjeremylt 
13839560d06aSjeremylt   @ref User
13849560d06aSjeremylt **/
13859560d06aSjeremylt int CeedReferenceCopy(Ceed ceed, Ceed *ceed_copy) {
13862b730f8bSJeremy L Thompson   CeedCall(CeedReference(ceed));
13872b730f8bSJeremy L Thompson   CeedCall(CeedDestroy(ceed_copy));
13889560d06aSjeremylt   *ceed_copy = ceed;
13899560d06aSjeremylt   return CEED_ERROR_SUCCESS;
13909560d06aSjeremylt }
13919560d06aSjeremylt 
13929560d06aSjeremylt /**
1393ca94c3ddSJeremy L Thompson   @brief Get the full resource name for a `Ceed` context
13942f86a920SJeremy L Thompson 
1395ca94c3ddSJeremy L Thompson   @param[in]  ceed     `Ceed` context to get resource name of
13967a982d89SJeremy L. Thompson   @param[out] resource Variable to store resource name
13972f86a920SJeremy L Thompson 
13982f86a920SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
13992f86a920SJeremy L Thompson 
14007a982d89SJeremy L. Thompson   @ref User
14015107b09fSJeremy L Thompson **/
14027a982d89SJeremy L. Thompson int CeedGetResource(Ceed ceed, const char **resource) {
14037a982d89SJeremy L. Thompson   *resource = (const char *)ceed->resource;
1404e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
14055107b09fSJeremy L Thompson }
14065107b09fSJeremy L Thompson 
14075107b09fSJeremy L Thompson /**
1408ca94c3ddSJeremy L Thompson   @brief Return `Ceed` context preferred memory type
1409c907536fSjeremylt 
1410ca94c3ddSJeremy L Thompson   @param[in]  ceed     `Ceed` context to get preferred memory type of
1411d1d35e2fSjeremylt   @param[out] mem_type Address to save preferred memory type to
1412c907536fSjeremylt 
1413c907536fSjeremylt   @return An error code: 0 - success, otherwise - failure
1414c907536fSjeremylt 
14157a982d89SJeremy L. Thompson   @ref User
1416c907536fSjeremylt **/
1417d1d35e2fSjeremylt int CeedGetPreferredMemType(Ceed ceed, CeedMemType *mem_type) {
1418c907536fSjeremylt   if (ceed->GetPreferredMemType) {
14192b730f8bSJeremy L Thompson     CeedCall(ceed->GetPreferredMemType(mem_type));
1420c907536fSjeremylt   } else {
1421c263cd57Sjeremylt     Ceed delegate;
14222b730f8bSJeremy L Thompson     CeedCall(CeedGetDelegate(ceed, &delegate));
1423c263cd57Sjeremylt 
1424c263cd57Sjeremylt     if (delegate) {
14252b730f8bSJeremy L Thompson       CeedCall(CeedGetPreferredMemType(delegate, mem_type));
1426c263cd57Sjeremylt     } else {
1427d1d35e2fSjeremylt       *mem_type = CEED_MEM_HOST;
1428c907536fSjeremylt     }
14299bc66399SJeremy L Thompson     CeedCall(CeedDestroy(&delegate));
1430c263cd57Sjeremylt   }
1431e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1432c907536fSjeremylt }
1433c907536fSjeremylt 
1434c907536fSjeremylt /**
1435ca94c3ddSJeremy L Thompson   @brief Get deterministic status of `Ceed` context
14369525855cSJeremy L Thompson 
1437ca94c3ddSJeremy L Thompson   @param[in]  ceed             `Ceed` context
1438d1d35e2fSjeremylt   @param[out] is_deterministic Variable to store deterministic status
14399525855cSJeremy L Thompson 
14409525855cSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
14419525855cSJeremy L Thompson 
14429525855cSJeremy L Thompson   @ref User
14439525855cSJeremy L Thompson **/
1444d1d35e2fSjeremylt int CeedIsDeterministic(Ceed ceed, bool *is_deterministic) {
1445d1d35e2fSjeremylt   *is_deterministic = ceed->is_deterministic;
1446e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
14479525855cSJeremy L Thompson }
14489525855cSJeremy L Thompson 
14499525855cSJeremy L Thompson /**
1450ca94c3ddSJeremy L Thompson   @brief Set additional JiT source root for `Ceed` context
1451ee5a26f2SJeremy L Thompson 
1452ca94c3ddSJeremy L Thompson   @param[in,out] ceed            `Ceed` context
1453ee5a26f2SJeremy L Thompson   @param[in]     jit_source_root Absolute path to additional JiT source directory
1454ee5a26f2SJeremy L Thompson 
1455ee5a26f2SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1456ee5a26f2SJeremy L Thompson 
1457ee5a26f2SJeremy L Thompson   @ref User
1458ee5a26f2SJeremy L Thompson **/
1459ee5a26f2SJeremy L Thompson int CeedAddJitSourceRoot(Ceed ceed, const char *jit_source_root) {
14606155f12fSJeremy L Thompson   Ceed ceed_parent;
1461ee5a26f2SJeremy L Thompson 
14622b730f8bSJeremy L Thompson   CeedCall(CeedGetParent(ceed, &ceed_parent));
1463830fc37bSJeremy 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");
14646155f12fSJeremy L Thompson 
14656155f12fSJeremy L Thompson   CeedInt index       = ceed_parent->num_jit_source_roots;
1466ee5a26f2SJeremy L Thompson   size_t  path_length = strlen(jit_source_root);
14671c66c397SJeremy L Thompson 
14684753b775SJeremy L Thompson   if (ceed_parent->num_jit_source_roots == ceed_parent->max_jit_source_roots) {
14694753b775SJeremy L Thompson     if (ceed_parent->max_jit_source_roots == 0) ceed_parent->max_jit_source_roots = 1;
14704753b775SJeremy L Thompson     ceed_parent->max_jit_source_roots *= 2;
14714753b775SJeremy L Thompson     CeedCall(CeedRealloc(ceed_parent->max_jit_source_roots, &ceed_parent->jit_source_roots));
14724753b775SJeremy L Thompson   }
14732b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(path_length + 1, &ceed_parent->jit_source_roots[index]));
1474d602d780SJeremy L Thompson   memcpy(ceed_parent->jit_source_roots[index], jit_source_root, path_length);
14756155f12fSJeremy L Thompson   ceed_parent->num_jit_source_roots++;
14769bc66399SJeremy L Thompson   CeedCall(CeedDestroy(&ceed_parent));
1477ee5a26f2SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1478ee5a26f2SJeremy L Thompson }
1479ee5a26f2SJeremy L Thompson 
1480ee5a26f2SJeremy L Thompson /**
14814753b775SJeremy L Thompson   @brief Set additional JiT compiler define for `Ceed` context
14824753b775SJeremy L Thompson 
14834753b775SJeremy L Thompson   @param[in,out] ceed       `Ceed` context
14844753b775SJeremy L Thompson   @param[in]     jit_define String such as `foo=bar`, used as `-Dfoo=bar` in JiT
14854753b775SJeremy L Thompson 
14864753b775SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
14874753b775SJeremy L Thompson 
14884753b775SJeremy L Thompson   @ref User
14894753b775SJeremy L Thompson **/
14904753b775SJeremy L Thompson int CeedAddJitDefine(Ceed ceed, const char *jit_define) {
14914753b775SJeremy L Thompson   Ceed ceed_parent;
14924753b775SJeremy L Thompson 
14934753b775SJeremy L Thompson   CeedCall(CeedGetParent(ceed, &ceed_parent));
1494830fc37bSJeremy L Thompson   CeedCheck(!ceed_parent->num_jit_defines_readers, ceed, CEED_ERROR_ACCESS, "Cannot add JiT define, read access has not been restored");
14954753b775SJeremy L Thompson 
14964753b775SJeremy L Thompson   CeedInt index         = ceed_parent->num_jit_defines;
14974753b775SJeremy L Thompson   size_t  define_length = strlen(jit_define);
14984753b775SJeremy L Thompson 
14994753b775SJeremy L Thompson   if (ceed_parent->num_jit_defines == ceed_parent->max_jit_defines) {
15004753b775SJeremy L Thompson     if (ceed_parent->max_jit_defines == 0) ceed_parent->max_jit_defines = 1;
15014753b775SJeremy L Thompson     ceed_parent->max_jit_defines *= 2;
15024753b775SJeremy L Thompson     CeedCall(CeedRealloc(ceed_parent->max_jit_defines, &ceed_parent->jit_defines));
15034753b775SJeremy L Thompson   }
15044753b775SJeremy L Thompson   CeedCall(CeedCalloc(define_length + 1, &ceed_parent->jit_defines[index]));
15054753b775SJeremy L Thompson   memcpy(ceed_parent->jit_defines[index], jit_define, define_length);
15064753b775SJeremy L Thompson   ceed_parent->num_jit_defines++;
15079bc66399SJeremy L Thompson   CeedCall(CeedDestroy(&ceed_parent));
15084753b775SJeremy L Thompson   return CEED_ERROR_SUCCESS;
15094753b775SJeremy L Thompson }
15104753b775SJeremy L Thompson 
15114753b775SJeremy L Thompson /**
1512ca94c3ddSJeremy L Thompson   @brief View a `Ceed`
15130a0da059Sjeremylt 
1514ca94c3ddSJeremy L Thompson   @param[in] ceed   `Ceed` to view
15150a0da059Sjeremylt   @param[in] stream Filestream to write to
15160a0da059Sjeremylt 
15170a0da059Sjeremylt   @return An error code: 0 - success, otherwise - failure
15180a0da059Sjeremylt 
15190a0da059Sjeremylt   @ref User
15200a0da059Sjeremylt **/
15210a0da059Sjeremylt int CeedView(Ceed ceed, FILE *stream) {
1522d1d35e2fSjeremylt   CeedMemType mem_type;
15230a0da059Sjeremylt 
15242b730f8bSJeremy L Thompson   CeedCall(CeedGetPreferredMemType(ceed, &mem_type));
15250a0da059Sjeremylt 
15262b730f8bSJeremy L Thompson   fprintf(stream,
15272b730f8bSJeremy L Thompson           "Ceed\n"
15280a0da059Sjeremylt           "  Ceed Resource: %s\n"
15290a0da059Sjeremylt           "  Preferred MemType: %s\n",
1530d1d35e2fSjeremylt           ceed->resource, CeedMemTypes[mem_type]);
1531e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
15320a0da059Sjeremylt }
15330a0da059Sjeremylt 
15340a0da059Sjeremylt /**
1535ca94c3ddSJeremy L Thompson   @brief Destroy a `Ceed`
1536d7b241e6Sjeremylt 
1537ca94c3ddSJeremy L Thompson   @param[in,out] ceed Address of `Ceed` context to destroy
1538b11c1e72Sjeremylt 
1539b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1540dfdf5a53Sjeremylt 
15417a982d89SJeremy L. Thompson   @ref User
1542b11c1e72Sjeremylt **/
1543d7b241e6Sjeremylt int CeedDestroy(Ceed *ceed) {
1544ad6481ceSJeremy L Thompson   if (!*ceed || --(*ceed)->ref_count > 0) {
1545ad6481ceSJeremy L Thompson     *ceed = NULL;
1546ad6481ceSJeremy L Thompson     return CEED_ERROR_SUCCESS;
1547ad6481ceSJeremy L Thompson   }
1548aeb3a72dSJeremy L Thompson 
1549aeb3a72dSJeremy L Thompson   CeedCheck(!(*ceed)->num_jit_source_roots_readers, *ceed, CEED_ERROR_ACCESS,
1550aeb3a72dSJeremy L Thompson             "Cannot destroy ceed context, read access for JiT source roots has been granted");
1551aeb3a72dSJeremy 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");
1552aeb3a72dSJeremy L Thompson 
15532b730f8bSJeremy L Thompson   if ((*ceed)->delegate) CeedCall(CeedDestroy(&(*ceed)->delegate));
15540ace9bf2Sjeremylt 
1555d1d35e2fSjeremylt   if ((*ceed)->obj_delegate_count > 0) {
155692ae7e47SJeremy L Thompson     for (CeedInt i = 0; i < (*ceed)->obj_delegate_count; i++) {
15572b730f8bSJeremy L Thompson       CeedCall(CeedDestroy(&((*ceed)->obj_delegates[i].delegate)));
15582b730f8bSJeremy L Thompson       CeedCall(CeedFree(&(*ceed)->obj_delegates[i].obj_name));
1559aefd8378Sjeremylt     }
15602b730f8bSJeremy L Thompson     CeedCall(CeedFree(&(*ceed)->obj_delegates));
1561aefd8378Sjeremylt   }
15620ace9bf2Sjeremylt 
15632b730f8bSJeremy L Thompson   if ((*ceed)->Destroy) CeedCall((*ceed)->Destroy(*ceed));
15640ace9bf2Sjeremylt 
156592ae7e47SJeremy L Thompson   for (CeedInt i = 0; i < (*ceed)->num_jit_source_roots; i++) {
15662b730f8bSJeremy L Thompson     CeedCall(CeedFree(&(*ceed)->jit_source_roots[i]));
1567032e71eaSJeremy L Thompson   }
15682b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*ceed)->jit_source_roots));
1569032e71eaSJeremy L Thompson 
15704753b775SJeremy L Thompson   for (CeedInt i = 0; i < (*ceed)->num_jit_defines; i++) {
15714753b775SJeremy L Thompson     CeedCall(CeedFree(&(*ceed)->jit_defines[i]));
15724753b775SJeremy L Thompson   }
15734753b775SJeremy L Thompson   CeedCall(CeedFree(&(*ceed)->jit_defines));
15744753b775SJeremy L Thompson 
15752b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*ceed)->f_offsets));
15762b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*ceed)->resource));
15772b730f8bSJeremy L Thompson   CeedCall(CeedDestroy(&(*ceed)->op_fallback_ceed));
15782b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*ceed)->op_fallback_resource));
157973501bfeSJeremy L Thompson   CeedCall(CeedWorkVectorsDestroy(*ceed));
15802b730f8bSJeremy L Thompson   CeedCall(CeedFree(ceed));
1581e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1582d7b241e6Sjeremylt }
1583d7b241e6Sjeremylt 
1584f9982c62SWill Pazner // LCOV_EXCL_START
1585f9982c62SWill Pazner const char *CeedErrorFormat(Ceed ceed, const char *format, va_list *args) {
15862b730f8bSJeremy L Thompson   if (ceed->parent) return CeedErrorFormat(ceed->parent, format, args);
15872b730f8bSJeremy L Thompson   if (ceed->op_fallback_parent) return CeedErrorFormat(ceed->op_fallback_parent, format, args);
158878464608Sjeremylt   // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized
158978464608Sjeremylt   vsnprintf(ceed->err_msg, CEED_MAX_RESOURCE_LEN, format, *args);  // NOLINT
1590d1d35e2fSjeremylt   return ceed->err_msg;
1591f9982c62SWill Pazner }
1592f9982c62SWill Pazner // LCOV_EXCL_STOP
1593f9982c62SWill Pazner 
15947a982d89SJeremy L. Thompson /**
1595ca94c3ddSJeremy L Thompson   @brief Error handling implementation; use @ref CeedError() instead.
1596ca94c3ddSJeremy L Thompson 
1597ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
15987a982d89SJeremy L. Thompson 
15997a982d89SJeremy L. Thompson   @ref Developer
16007a982d89SJeremy L. Thompson **/
16012b730f8bSJeremy L Thompson int CeedErrorImpl(Ceed ceed, const char *filename, int lineno, const char *func, int ecode, const char *format, ...) {
16027a982d89SJeremy L. Thompson   va_list args;
1603d1d35e2fSjeremylt   int     ret_val;
16041c66c397SJeremy L Thompson 
16057a982d89SJeremy L. Thompson   va_start(args, format);
16067a982d89SJeremy L. Thompson   if (ceed) {
1607d1d35e2fSjeremylt     ret_val = ceed->Error(ceed, filename, lineno, func, ecode, format, &args);
16087a982d89SJeremy L. Thompson   } else {
1609b0d62198Sjeremylt     // LCOV_EXCL_START
1610477729cfSJeremy L Thompson     const char *ceed_error_handler = getenv("CEED_ERROR_HANDLER");
16112b730f8bSJeremy L Thompson     if (!ceed_error_handler) ceed_error_handler = "abort";
1612bcbe1c99SJeremy L Thompson     if (!strcmp(ceed_error_handler, "return")) {
1613bcbe1c99SJeremy L Thompson       ret_val = CeedErrorReturn(ceed, filename, lineno, func, ecode, format, &args);
1614bcbe1c99SJeremy L Thompson     } else {
1615477729cfSJeremy L Thompson       // This function will not return
1616d1d35e2fSjeremylt       ret_val = CeedErrorAbort(ceed, filename, lineno, func, ecode, format, &args);
16177a982d89SJeremy L. Thompson     }
1618bcbe1c99SJeremy L Thompson   }
16197a982d89SJeremy L. Thompson   va_end(args);
1620d1d35e2fSjeremylt   return ret_val;
1621b0d62198Sjeremylt   // LCOV_EXCL_STOP
16227a982d89SJeremy L. Thompson }
16237a982d89SJeremy L. Thompson 
1624477729cfSJeremy L Thompson /**
1625477729cfSJeremy L Thompson   @brief Error handler that returns without printing anything.
1626477729cfSJeremy L Thompson 
1627ca94c3ddSJeremy L Thompson   Pass this to @ref CeedSetErrorHandler() to obtain this error handling behavior.
1628ca94c3ddSJeremy L Thompson 
1629ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1630477729cfSJeremy L Thompson 
1631477729cfSJeremy L Thompson   @ref Developer
1632477729cfSJeremy L Thompson **/
1633477729cfSJeremy L Thompson // LCOV_EXCL_START
16342b730f8bSJeremy L Thompson int CeedErrorReturn(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) {
1635d1d35e2fSjeremylt   return err_code;
1636477729cfSJeremy L Thompson }
1637477729cfSJeremy L Thompson // LCOV_EXCL_STOP
1638477729cfSJeremy L Thompson 
1639477729cfSJeremy L Thompson /**
1640ea61e9acSJeremy L Thompson   @brief Error handler that stores the error message for future use and returns the error.
1641477729cfSJeremy L Thompson 
1642ca94c3ddSJeremy L Thompson   Pass this to @ref CeedSetErrorHandler() to obtain this error handling behavior.
1643ca94c3ddSJeremy L Thompson 
1644ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1645477729cfSJeremy L Thompson 
1646477729cfSJeremy L Thompson   @ref Developer
1647477729cfSJeremy L Thompson **/
1648477729cfSJeremy L Thompson // LCOV_EXCL_START
16492b730f8bSJeremy L Thompson int CeedErrorStore(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) {
16502b730f8bSJeremy L Thompson   if (ceed->parent) return CeedErrorStore(ceed->parent, filename, line_no, func, err_code, format, args);
16512b730f8bSJeremy L Thompson   if (ceed->op_fallback_parent) return CeedErrorStore(ceed->op_fallback_parent, filename, line_no, func, err_code, format, args);
1652477729cfSJeremy L Thompson 
1653477729cfSJeremy L Thompson   // Build message
16541c66c397SJeremy L Thompson   int len = snprintf(ceed->err_msg, CEED_MAX_RESOURCE_LEN, "%s:%d in %s(): ", filename, line_no, func);
165578464608Sjeremylt   // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized
165678464608Sjeremylt   vsnprintf(ceed->err_msg + len, CEED_MAX_RESOURCE_LEN - len, format, *args);  // NOLINT
1657d1d35e2fSjeremylt   return err_code;
1658477729cfSJeremy L Thompson }
1659477729cfSJeremy L Thompson // LCOV_EXCL_STOP
1660477729cfSJeremy L Thompson 
1661477729cfSJeremy L Thompson /**
1662ca94c3ddSJeremy L Thompson   @brief Error handler that prints to `stderr` and aborts
1663477729cfSJeremy L Thompson 
1664ca94c3ddSJeremy L Thompson   Pass this to @ref CeedSetErrorHandler() to obtain this error handling behavior.
1665ca94c3ddSJeremy L Thompson 
1666ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1667477729cfSJeremy L Thompson 
1668477729cfSJeremy L Thompson   @ref Developer
1669477729cfSJeremy L Thompson **/
1670477729cfSJeremy L Thompson // LCOV_EXCL_START
16712b730f8bSJeremy L Thompson int CeedErrorAbort(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) {
1672d1d35e2fSjeremylt   fprintf(stderr, "%s:%d in %s(): ", filename, line_no, func);
1673f9982c62SWill Pazner   vfprintf(stderr, format, *args);
1674477729cfSJeremy L Thompson   fprintf(stderr, "\n");
1675477729cfSJeremy L Thompson   abort();
1676d1d35e2fSjeremylt   return err_code;
1677477729cfSJeremy L Thompson }
1678477729cfSJeremy L Thompson // LCOV_EXCL_STOP
1679477729cfSJeremy L Thompson 
1680477729cfSJeremy L Thompson /**
1681ca94c3ddSJeremy L Thompson   @brief Error handler that prints to `stderr` and exits.
1682477729cfSJeremy L Thompson 
1683ca94c3ddSJeremy L Thompson   Pass this to @ref CeedSetErrorHandler() to obtain this error handling behavior.
1684477729cfSJeremy L Thompson 
1685ca94c3ddSJeremy L Thompson   In contrast to @ref CeedErrorAbort(), this exits without a signal, so `atexit()` handlers (e.g., as used by gcov) are run.
1686ca94c3ddSJeremy L Thompson 
1687ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1688477729cfSJeremy L Thompson 
1689477729cfSJeremy L Thompson   @ref Developer
1690477729cfSJeremy L Thompson **/
16912b730f8bSJeremy L Thompson int CeedErrorExit(Ceed ceed, const char *filename, int line_no, const char *func, int err_code, const char *format, va_list *args) {
1692d1d35e2fSjeremylt   fprintf(stderr, "%s:%d in %s(): ", filename, line_no, func);
169378464608Sjeremylt   // Using pointer to va_list for better FFI, but clang-tidy can't verify va_list is initalized
169478464608Sjeremylt   vfprintf(stderr, format, *args);  // NOLINT
1695477729cfSJeremy L Thompson   fprintf(stderr, "\n");
1696d1d35e2fSjeremylt   exit(err_code);
1697d1d35e2fSjeremylt   return err_code;
1698477729cfSJeremy L Thompson }
1699477729cfSJeremy L Thompson 
1700477729cfSJeremy L Thompson /**
1701477729cfSJeremy L Thompson   @brief Set error handler
1702477729cfSJeremy L Thompson 
1703ca94c3ddSJeremy L Thompson   A default error handler is set in @ref CeedInit().
1704ca94c3ddSJeremy L Thompson   Use this function to change the error handler to @ref CeedErrorReturn(), @ref CeedErrorAbort(), or a user-defined error handler.
1705ca94c3ddSJeremy L Thompson 
1706ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1707477729cfSJeremy L Thompson 
1708477729cfSJeremy L Thompson   @ref Developer
1709477729cfSJeremy L Thompson **/
1710d1d35e2fSjeremylt int CeedSetErrorHandler(Ceed ceed, CeedErrorHandler handler) {
1711d1d35e2fSjeremylt   ceed->Error = handler;
1712d1d35e2fSjeremylt   if (ceed->delegate) CeedSetErrorHandler(ceed->delegate, handler);
17132b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < ceed->obj_delegate_count; i++) CeedSetErrorHandler(ceed->obj_delegates[i].delegate, handler);
1714e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1715477729cfSJeremy L Thompson }
1716477729cfSJeremy L Thompson 
1717477729cfSJeremy L Thompson /**
1718477729cfSJeremy L Thompson   @brief Get error message
1719477729cfSJeremy L Thompson 
1720ca94c3ddSJeremy L Thompson   The error message is only stored when using the error handler @ref CeedErrorStore()
1721477729cfSJeremy L Thompson 
1722ca94c3ddSJeremy L Thompson   @param[in]  ceed    `Ceed` context to retrieve error message
1723d1d35e2fSjeremylt   @param[out] err_msg Char pointer to hold error message
1724477729cfSJeremy L Thompson 
1725ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1726ca94c3ddSJeremy L Thompson 
1727477729cfSJeremy L Thompson   @ref Developer
1728477729cfSJeremy L Thompson **/
1729d1d35e2fSjeremylt int CeedGetErrorMessage(Ceed ceed, const char **err_msg) {
17302b730f8bSJeremy L Thompson   if (ceed->parent) return CeedGetErrorMessage(ceed->parent, err_msg);
17312b730f8bSJeremy L Thompson   if (ceed->op_fallback_parent) return CeedGetErrorMessage(ceed->op_fallback_parent, err_msg);
1732d1d35e2fSjeremylt   *err_msg = ceed->err_msg;
1733e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1734477729cfSJeremy L Thompson }
1735477729cfSJeremy L Thompson 
1736477729cfSJeremy L Thompson /**
1737ca94c3ddSJeremy L Thompson   @brief Restore error message.
1738477729cfSJeremy L Thompson 
1739ca94c3ddSJeremy L Thompson   The error message is only stored when using the error handler @ref CeedErrorStore().
1740477729cfSJeremy L Thompson 
1741ca94c3ddSJeremy L Thompson   @param[in]  ceed    `Ceed` context to restore error message
1742d1d35e2fSjeremylt   @param[out] err_msg Char pointer that holds error message
1743477729cfSJeremy L Thompson 
1744ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1745ca94c3ddSJeremy L Thompson 
1746477729cfSJeremy L Thompson   @ref Developer
1747477729cfSJeremy L Thompson **/
1748d1d35e2fSjeremylt int CeedResetErrorMessage(Ceed ceed, const char **err_msg) {
17492b730f8bSJeremy L Thompson   if (ceed->parent) return CeedResetErrorMessage(ceed->parent, err_msg);
17502b730f8bSJeremy L Thompson   if (ceed->op_fallback_parent) return CeedResetErrorMessage(ceed->op_fallback_parent, err_msg);
1751d1d35e2fSjeremylt   *err_msg = NULL;
1752d1d35e2fSjeremylt   memcpy(ceed->err_msg, "No error message stored", 24);
1753e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1754477729cfSJeremy L Thompson }
1755477729cfSJeremy L Thompson 
17561070991dSJed Brown /**
1757ca94c3ddSJeremy L Thompson   @brief Get libCEED library version information.
17581070991dSJed Brown 
1759ea61e9acSJeremy L Thompson   libCEED version numbers have the form major.minor.patch.
1760ea61e9acSJeremy L Thompson   Non-release versions may contain unstable interfaces.
17611070991dSJed Brown 
17621070991dSJed Brown   @param[out] major   Major version of the library
17631070991dSJed Brown   @param[out] minor   Minor version of the library
17641070991dSJed Brown   @param[out] patch   Patch (subminor) version of the library
176553cbfc38SJeremy L Thompson   @param[out] release True for releases; false for development branches
17661070991dSJed Brown 
1767ca94c3ddSJeremy L Thompson   The caller may pass `NULL` for any arguments that are not needed.
17681070991dSJed Brown 
1769ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
17701070991dSJed Brown 
17711070991dSJed Brown   @ref Developer
1772ca94c3ddSJeremy L Thompson 
17734f69910bSJed Brown   @sa CEED_VERSION_GE() CeedGetGitVersion() CeedGetBuildConfiguration()
17741070991dSJed Brown */
17751070991dSJed Brown int CeedGetVersion(int *major, int *minor, int *patch, bool *release) {
17761070991dSJed Brown   if (major) *major = CEED_VERSION_MAJOR;
17771070991dSJed Brown   if (minor) *minor = CEED_VERSION_MINOR;
17781070991dSJed Brown   if (patch) *patch = CEED_VERSION_PATCH;
17791070991dSJed Brown   if (release) *release = CEED_VERSION_RELEASE;
1780ca94c3ddSJeremy L Thompson   return CEED_ERROR_SUCCESS;
17811070991dSJed Brown }
17821070991dSJed Brown 
178353cbfc38SJeremy L Thompson /**
178453cbfc38SJeremy L Thompson   @brief Get libCEED scalar type, such as F64 or F32
178553cbfc38SJeremy L Thompson 
178653cbfc38SJeremy L Thompson   @param[out] scalar_type Type of libCEED scalars
178753cbfc38SJeremy L Thompson 
1788ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1789ca94c3ddSJeremy L Thompson 
179053cbfc38SJeremy L Thompson   @ref Developer
179153cbfc38SJeremy L Thompson */
179280a9ef05SNatalie Beams int CeedGetScalarType(CeedScalarType *scalar_type) {
179380a9ef05SNatalie Beams   *scalar_type = CEED_SCALAR_TYPE;
1794ca94c3ddSJeremy L Thompson   return CEED_ERROR_SUCCESS;
179580a9ef05SNatalie Beams }
179680a9ef05SNatalie Beams 
1797d7b241e6Sjeremylt /// @}
1798