xref: /libCEED/rust/libceed-sys/c-src/interface/ceed-elemrestriction.c (revision c7745053b0774c228ac7429b6b3e5eca9baa354c)
1d7b241e6Sjeremylt // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at
2d7b241e6Sjeremylt // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
3d7b241e6Sjeremylt // reserved. See files LICENSE and NOTICE for details.
4d7b241e6Sjeremylt //
5d7b241e6Sjeremylt // This file is part of CEED, a collection of benchmarks, miniapps, software
6d7b241e6Sjeremylt // libraries and APIs for efficient high-order finite element and spectral
7d7b241e6Sjeremylt // element discretizations for exascale applications. For more information and
8d7b241e6Sjeremylt // source code availability see http://github.com/ceed.
9d7b241e6Sjeremylt //
10d7b241e6Sjeremylt // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
11d7b241e6Sjeremylt // a collaborative effort of two U.S. Department of Energy organizations (Office
12d7b241e6Sjeremylt // of Science and the National Nuclear Security Administration) responsible for
13d7b241e6Sjeremylt // the planning and preparation of a capable exascale ecosystem, including
14d7b241e6Sjeremylt // software, applications, hardware, advanced system engineering and early
15d7b241e6Sjeremylt // testbed platforms, in support of the nation's exascale computing imperative.
16d7b241e6Sjeremylt 
17ec3da8bcSJed Brown #include <ceed/ceed.h>
18ec3da8bcSJed Brown #include <ceed/backend.h>
193d576824SJeremy L Thompson #include <ceed-impl.h>
203d576824SJeremy L Thompson #include <stdbool.h>
213d576824SJeremy L Thompson #include <stdio.h>
22d7b241e6Sjeremylt 
237a982d89SJeremy L. Thompson /// @file
247a982d89SJeremy L. Thompson /// Implementation of CeedElemRestriction interfaces
257a982d89SJeremy L. Thompson 
267a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
277a982d89SJeremy L. Thompson /// CeedElemRestriction Library Internal Functions
287a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
297a982d89SJeremy L. Thompson /// @addtogroup CeedElemRestrictionDeveloper
307a982d89SJeremy L. Thompson /// @{
317a982d89SJeremy L. Thompson 
327a982d89SJeremy L. Thompson /**
33d979a051Sjeremylt   @brief Permute and pad offsets for a blocked restriction
347a982d89SJeremy L. Thompson 
35d1d35e2fSjeremylt   @param offsets     Array of shape [@a num_elem, @a elem_size]. Row i holds the
36d979a051Sjeremylt                        ordered list of the offsets (into the input CeedVector)
377a982d89SJeremy L. Thompson                        for the unknowns corresponding to element i, where
38d1d35e2fSjeremylt                        0 <= i < @a num_elem. All offsets must be in the range
39d1d35e2fSjeremylt                        [0, @a l_size - 1].
40d1d35e2fSjeremylt   @param blk_offsets Array of permuted and padded offsets of
41d1d35e2fSjeremylt                        shape [@a num_blk, @a elem_size, @a blk_size].
42d1d35e2fSjeremylt   @param num_blk     Number of blocks
43d1d35e2fSjeremylt   @param num_elem    Number of elements
44d1d35e2fSjeremylt   @param blk_size    Number of elements in a block
45d1d35e2fSjeremylt   @param elem_size   Size of each element
467a982d89SJeremy L. Thompson 
477a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
487a982d89SJeremy L. Thompson 
497a982d89SJeremy L. Thompson   @ref Utility
507a982d89SJeremy L. Thompson **/
51d1d35e2fSjeremylt int CeedPermutePadOffsets(const CeedInt *offsets, CeedInt *blk_offsets,
52d1d35e2fSjeremylt                           CeedInt num_blk, CeedInt num_elem, CeedInt blk_size,
53d1d35e2fSjeremylt                           CeedInt elem_size) {
54d1d35e2fSjeremylt   for (CeedInt e=0; e<num_blk*blk_size; e+=blk_size)
55d1d35e2fSjeremylt     for (int j=0; j<blk_size; j++)
56d1d35e2fSjeremylt       for (int k=0; k<elem_size; k++)
57d1d35e2fSjeremylt         blk_offsets[e*elem_size + k*blk_size + j]
58d1d35e2fSjeremylt           = offsets[CeedIntMin(e+j,num_elem-1)*elem_size + k];
59e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
607a982d89SJeremy L. Thompson }
617a982d89SJeremy L. Thompson 
627a982d89SJeremy L. Thompson /// @}
637a982d89SJeremy L. Thompson 
647a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
657a982d89SJeremy L. Thompson /// CeedElemRestriction Backend API
667a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
677a982d89SJeremy L. Thompson /// @addtogroup CeedElemRestrictionBackend
687a982d89SJeremy L. Thompson /// @{
697a982d89SJeremy L. Thompson 
707a982d89SJeremy L. Thompson /**
71a681ae63Sjeremylt 
72a681ae63Sjeremylt   @brief Get the strides of a strided CeedElemRestriction
737a982d89SJeremy L. Thompson 
747a982d89SJeremy L. Thompson   @param rstr          CeedElemRestriction
75a681ae63Sjeremylt   @param[out] strides  Variable to store strides array
767a982d89SJeremy L. Thompson 
777a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
787a982d89SJeremy L. Thompson 
797a982d89SJeremy L. Thompson   @ref Backend
807a982d89SJeremy L. Thompson **/
81a681ae63Sjeremylt int CeedElemRestrictionGetStrides(CeedElemRestriction rstr,
82a681ae63Sjeremylt                                   CeedInt (*strides)[3]) {
83a681ae63Sjeremylt   if (!rstr->strides)
84a681ae63Sjeremylt     // LCOV_EXCL_START
85e15f9bd0SJeremy L Thompson     return CeedError(rstr->ceed, CEED_ERROR_MINOR,
86e15f9bd0SJeremy L Thompson                      "ElemRestriction has no stride data");
87a681ae63Sjeremylt   // LCOV_EXCL_STOP
88a681ae63Sjeremylt 
89a681ae63Sjeremylt   for (int i=0; i<3; i++)
90a681ae63Sjeremylt     (*strides)[i] = rstr->strides[i];
91e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
927a982d89SJeremy L. Thompson }
937a982d89SJeremy L. Thompson 
947a982d89SJeremy L. Thompson /**
95bd33150aSjeremylt   @brief Get read-only access to a CeedElemRestriction offsets array by memtype
96bd33150aSjeremylt 
97bd33150aSjeremylt   @param rstr          CeedElemRestriction to retrieve offsets
98d1d35e2fSjeremylt   @param mem_type      Memory type on which to access the array.  If the backend
99bd33150aSjeremylt                          uses a different memory type, this will perform a copy
100bd33150aSjeremylt                          (possibly cached).
101d1d35e2fSjeremylt   @param[out] offsets  Array on memory type mem_type
102bd33150aSjeremylt 
103bd33150aSjeremylt   @return An error code: 0 - success, otherwise - failure
104bd33150aSjeremylt 
105bd33150aSjeremylt   @ref User
106bd33150aSjeremylt **/
107d1d35e2fSjeremylt int CeedElemRestrictionGetOffsets(CeedElemRestriction rstr,
108d1d35e2fSjeremylt                                   CeedMemType mem_type,
109bd33150aSjeremylt                                   const CeedInt **offsets) {
110bd33150aSjeremylt   int ierr;
111bd33150aSjeremylt 
112bd33150aSjeremylt   if (!rstr->GetOffsets)
113bd33150aSjeremylt     // LCOV_EXCL_START
114e15f9bd0SJeremy L Thompson     return CeedError(rstr->ceed, CEED_ERROR_UNSUPPORTED,
115e15f9bd0SJeremy L Thompson                      "Backend does not support GetOffsets");
116bd33150aSjeremylt   // LCOV_EXCL_STOP
117bd33150aSjeremylt 
118d1d35e2fSjeremylt   ierr = rstr->GetOffsets(rstr, mem_type, offsets); CeedChk(ierr);
119d1d35e2fSjeremylt   rstr->num_readers++;
120e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
121430758c8SJeremy L Thompson }
122430758c8SJeremy L Thompson 
123430758c8SJeremy L Thompson /**
124430758c8SJeremy L Thompson   @brief Restore an offsets array obtained using CeedElemRestrictionGetOffsets()
125430758c8SJeremy L Thompson 
126430758c8SJeremy L Thompson   @param rstr     CeedElemRestriction to restore
127430758c8SJeremy L Thompson   @param offsets  Array of offset data
128430758c8SJeremy L Thompson 
129430758c8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
130430758c8SJeremy L Thompson 
131430758c8SJeremy L Thompson   @ref User
132430758c8SJeremy L Thompson **/
133430758c8SJeremy L Thompson int CeedElemRestrictionRestoreOffsets(CeedElemRestriction rstr,
134430758c8SJeremy L Thompson                                       const CeedInt **offsets) {
135430758c8SJeremy L Thompson   *offsets = NULL;
136d1d35e2fSjeremylt   rstr->num_readers--;
137e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
138bd33150aSjeremylt }
139bd33150aSjeremylt 
140bd33150aSjeremylt /**
1413ac43b2cSJeremy L Thompson   @brief Get the strided status of a CeedElemRestriction
1423ac43b2cSJeremy L Thompson 
1433ac43b2cSJeremy L Thompson   @param rstr             CeedElemRestriction
144d1d35e2fSjeremylt   @param[out] is_strided  Variable to store strided status, 1 if strided else 0
1453ac43b2cSJeremy L Thompson 
1463ac43b2cSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1473ac43b2cSJeremy L Thompson 
1483ac43b2cSJeremy L Thompson   @ref Backend
1493ac43b2cSJeremy L Thompson **/
150d1d35e2fSjeremylt int CeedElemRestrictionIsStrided(CeedElemRestriction rstr, bool *is_strided) {
151d1d35e2fSjeremylt   *is_strided = rstr->strides ? true : false;
152e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1533ac43b2cSJeremy L Thompson }
1543ac43b2cSJeremy L Thompson 
1553ac43b2cSJeremy L Thompson /**
156a681ae63Sjeremylt   @brief Get the backend stride status of a CeedElemRestriction
1577a982d89SJeremy L. Thompson 
1587a982d89SJeremy L. Thompson   @param rstr                      CeedElemRestriction
15996b902e2Sjeremylt   @param[out] has_backend_strides  Variable to store stride status
1607a982d89SJeremy L. Thompson 
1617a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1627a982d89SJeremy L. Thompson 
1637a982d89SJeremy L. Thompson   @ref Backend
1647a982d89SJeremy L. Thompson **/
165fd364f38SJeremy L Thompson int CeedElemRestrictionHasBackendStrides(CeedElemRestriction rstr,
166d1d35e2fSjeremylt     bool *has_backend_strides) {
167a681ae63Sjeremylt   if (!rstr->strides)
168a681ae63Sjeremylt     // LCOV_EXCL_START
169e15f9bd0SJeremy L Thompson     return CeedError(rstr->ceed, CEED_ERROR_MINOR,
170e15f9bd0SJeremy L Thompson                      "ElemRestriction has no stride data");
171a681ae63Sjeremylt   // LCOV_EXCL_STOP
1727a982d89SJeremy L. Thompson 
173d1d35e2fSjeremylt   *has_backend_strides = ((rstr->strides[0] == CEED_STRIDES_BACKEND[0]) &&
174a681ae63Sjeremylt                           (rstr->strides[1] == CEED_STRIDES_BACKEND[1]) &&
175a681ae63Sjeremylt                           (rstr->strides[2] == CEED_STRIDES_BACKEND[2]));
176e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1777a982d89SJeremy L. Thompson }
1787a982d89SJeremy L. Thompson 
1797a982d89SJeremy L. Thompson /**
18049fd234cSJeremy L Thompson 
18149fd234cSJeremy L Thompson   @brief Get the E-vector layout of a CeedElemRestriction
18249fd234cSJeremy L Thompson 
18349fd234cSJeremy L Thompson   @param rstr         CeedElemRestriction
18449fd234cSJeremy L Thompson   @param[out] layout  Variable to store layout array,
18549fd234cSJeremy L Thompson                         stored as [nodes, components, elements].
18649fd234cSJeremy L Thompson                         The data for node i, component j, element k in the
18749fd234cSJeremy L Thompson                         E-vector is given by
18895e93d34SJeremy L Thompson                         i*layout[0] + j*layout[1] + k*layout[2]
18949fd234cSJeremy L Thompson 
19049fd234cSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
19149fd234cSJeremy L Thompson 
19249fd234cSJeremy L Thompson   @ref Backend
19349fd234cSJeremy L Thompson **/
19449fd234cSJeremy L Thompson int CeedElemRestrictionGetELayout(CeedElemRestriction rstr,
19549fd234cSJeremy L Thompson                                   CeedInt (*layout)[3]) {
19649fd234cSJeremy L Thompson   if (!rstr->layout[0])
19749fd234cSJeremy L Thompson     // LCOV_EXCL_START
198e15f9bd0SJeremy L Thompson     return CeedError(rstr->ceed, CEED_ERROR_MINOR,
199e15f9bd0SJeremy L Thompson                      "ElemRestriction has no layout data");
20049fd234cSJeremy L Thompson   // LCOV_EXCL_STOP
20149fd234cSJeremy L Thompson 
20249fd234cSJeremy L Thompson   for (int i=0; i<3; i++)
20349fd234cSJeremy L Thompson     (*layout)[i] = rstr->layout[i];
204e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
20549fd234cSJeremy L Thompson }
20649fd234cSJeremy L Thompson 
20749fd234cSJeremy L Thompson /**
20849fd234cSJeremy L Thompson 
20949fd234cSJeremy L Thompson   @brief Set the E-vector layout of a CeedElemRestriction
21049fd234cSJeremy L Thompson 
21149fd234cSJeremy L Thompson   @param rstr    CeedElemRestriction
21249fd234cSJeremy L Thompson   @param layout  Variable to containing layout array,
21349fd234cSJeremy L Thompson                    stored as [nodes, components, elements].
21449fd234cSJeremy L Thompson                    The data for node i, component j, element k in the
21549fd234cSJeremy L Thompson                    E-vector is given by
21695e93d34SJeremy L Thompson                    i*layout[0] + j*layout[1] + k*layout[2]
21749fd234cSJeremy L Thompson 
21849fd234cSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
21949fd234cSJeremy L Thompson 
22049fd234cSJeremy L Thompson   @ref Backend
22149fd234cSJeremy L Thompson **/
22249fd234cSJeremy L Thompson int CeedElemRestrictionSetELayout(CeedElemRestriction rstr,
22349fd234cSJeremy L Thompson                                   CeedInt layout[3]) {
22449fd234cSJeremy L Thompson   for (int i = 0; i<3; i++)
22549fd234cSJeremy L Thompson     rstr->layout[i] = layout[i];
226e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
22749fd234cSJeremy L Thompson }
22849fd234cSJeremy L Thompson 
22949fd234cSJeremy L Thompson /**
2307a982d89SJeremy L. Thompson   @brief Get the backend data of a CeedElemRestriction
2317a982d89SJeremy L. Thompson 
2327a982d89SJeremy L. Thompson   @param rstr       CeedElemRestriction
2337a982d89SJeremy L. Thompson   @param[out] data  Variable to store data
2347a982d89SJeremy L. Thompson 
2357a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
2367a982d89SJeremy L. Thompson 
2377a982d89SJeremy L. Thompson   @ref Backend
2387a982d89SJeremy L. Thompson **/
239777ff853SJeremy L Thompson int CeedElemRestrictionGetData(CeedElemRestriction rstr, void *data) {
240777ff853SJeremy L Thompson   *(void **)data = rstr->data;
241e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2427a982d89SJeremy L. Thompson }
2437a982d89SJeremy L. Thompson 
2447a982d89SJeremy L. Thompson /**
2457a982d89SJeremy L. Thompson   @brief Set the backend data of a CeedElemRestriction
2467a982d89SJeremy L. Thompson 
2477a982d89SJeremy L. Thompson   @param[out] rstr  CeedElemRestriction
2487a982d89SJeremy L. Thompson   @param data       Data to set
2497a982d89SJeremy L. Thompson 
2507a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
2517a982d89SJeremy L. Thompson 
2527a982d89SJeremy L. Thompson   @ref Backend
2537a982d89SJeremy L. Thompson **/
254777ff853SJeremy L Thompson int CeedElemRestrictionSetData(CeedElemRestriction rstr, void *data) {
255777ff853SJeremy L Thompson   rstr->data = data;
256e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2577a982d89SJeremy L. Thompson }
2587a982d89SJeremy L. Thompson 
25934359f16Sjeremylt /**
26034359f16Sjeremylt   @brief Increment the reference counter for a CeedElemRestriction
26134359f16Sjeremylt 
26234359f16Sjeremylt   @param rstr  ElemRestriction to increment the reference counter
26334359f16Sjeremylt 
26434359f16Sjeremylt   @return An error code: 0 - success, otherwise - failure
26534359f16Sjeremylt 
26634359f16Sjeremylt   @ref Backend
26734359f16Sjeremylt **/
2689560d06aSjeremylt int CeedElemRestrictionReference(CeedElemRestriction rstr) {
26934359f16Sjeremylt   rstr->ref_count++;
27034359f16Sjeremylt   return CEED_ERROR_SUCCESS;
27134359f16Sjeremylt }
27234359f16Sjeremylt 
2737a982d89SJeremy L. Thompson /// @}
2747a982d89SJeremy L. Thompson 
27515910d16Sjeremylt /// @cond DOXYGEN_SKIP
27615910d16Sjeremylt static struct CeedElemRestriction_private ceed_elemrestriction_none;
27715910d16Sjeremylt /// @endcond
27815910d16Sjeremylt 
2797a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
2807a982d89SJeremy L. Thompson /// CeedElemRestriction Public API
2817a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
2827a982d89SJeremy L. Thompson /// @addtogroup CeedElemRestrictionUser
283d7b241e6Sjeremylt /// @{
284d7b241e6Sjeremylt 
2857a982d89SJeremy L. Thompson /// Indicate that the stride is determined by the backend
28645f1e315Sjeremylt const CeedInt CEED_STRIDES_BACKEND[3] = {0};
2877a982d89SJeremy L. Thompson 
2884cc79fe7SJed Brown /// Indicate that no CeedElemRestriction is provided by the user
2897a982d89SJeremy L. Thompson const CeedElemRestriction CEED_ELEMRESTRICTION_NONE =
2907a982d89SJeremy L. Thompson   &ceed_elemrestriction_none;
2917a982d89SJeremy L. Thompson 
292d7b241e6Sjeremylt /**
293b11c1e72Sjeremylt   @brief Create a CeedElemRestriction
294d7b241e6Sjeremylt 
295b11c1e72Sjeremylt   @param ceed         A Ceed object where the CeedElemRestriction will be created
296d1d35e2fSjeremylt   @param num_elem     Number of elements described in the @a offsets array
297d1d35e2fSjeremylt   @param elem_size    Size (number of "nodes") per element
298d1d35e2fSjeremylt   @param num_comp     Number of field components per interpolation node
29995bb1877Svaleriabarra                         (1 for scalar fields)
300d1d35e2fSjeremylt   @param comp_stride  Stride between components for the same L-vector "node".
30195e93d34SJeremy L Thompson                         Data for node i, component j, element k can be found in
30295e93d34SJeremy L Thompson                         the L-vector at index
303d1d35e2fSjeremylt                         offsets[i + k*elem_size] + j*comp_stride.
304d1d35e2fSjeremylt   @param l_size       The size of the L-vector. This vector may be larger than
305d979a051Sjeremylt                         the elements and fields given by this restriction.
306d1d35e2fSjeremylt   @param mem_type     Memory type of the @a offsets array, see CeedMemType
307d1d35e2fSjeremylt   @param copy_mode    Copy mode for the @a offsets array, see CeedCopyMode
308d1d35e2fSjeremylt   @param offsets      Array of shape [@a num_elem, @a elem_size]. Row i holds the
309d979a051Sjeremylt                         ordered list of the offsets (into the input CeedVector)
3108795c945Sjeremylt                         for the unknowns corresponding to element i, where
311d1d35e2fSjeremylt                         0 <= i < @a num_elem. All offsets must be in the range
312d1d35e2fSjeremylt                         [0, @a l_size - 1].
3134ce2993fSjeremylt   @param[out] rstr    Address of the variable where the newly created
314b11c1e72Sjeremylt                         CeedElemRestriction will be stored
315d7b241e6Sjeremylt 
316b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
317dfdf5a53Sjeremylt 
3187a982d89SJeremy L. Thompson   @ref User
319b11c1e72Sjeremylt **/
320d1d35e2fSjeremylt int CeedElemRestrictionCreate(Ceed ceed, CeedInt num_elem, CeedInt elem_size,
321d1d35e2fSjeremylt                               CeedInt num_comp, CeedInt comp_stride,
322d1d35e2fSjeremylt                               CeedInt l_size, CeedMemType mem_type,
323d1d35e2fSjeremylt                               CeedCopyMode copy_mode, const CeedInt *offsets,
3244ce2993fSjeremylt                               CeedElemRestriction *rstr) {
325d7b241e6Sjeremylt   int ierr;
326d7b241e6Sjeremylt 
3275fe0d4faSjeremylt   if (!ceed->ElemRestrictionCreate) {
3285fe0d4faSjeremylt     Ceed delegate;
329aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
330aefd8378Sjeremylt     CeedChk(ierr);
3315fe0d4faSjeremylt 
3325fe0d4faSjeremylt     if (!delegate)
333c042f62fSJeremy L Thompson       // LCOV_EXCL_START
334e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
335e15f9bd0SJeremy L Thompson                        "Backend does not support ElemRestrictionCreate");
336c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
3375fe0d4faSjeremylt 
338d1d35e2fSjeremylt     ierr = CeedElemRestrictionCreate(delegate, num_elem, elem_size, num_comp,
339d1d35e2fSjeremylt                                      comp_stride, l_size, mem_type, copy_mode,
340d979a051Sjeremylt                                      offsets, rstr); CeedChk(ierr);
341e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
3425fe0d4faSjeremylt   }
3435fe0d4faSjeremylt 
3444ce2993fSjeremylt   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
3454ce2993fSjeremylt   (*rstr)->ceed = ceed;
3469560d06aSjeremylt   ierr = CeedReference(ceed); CeedChk(ierr);
347d1d35e2fSjeremylt   (*rstr)->ref_count = 1;
348d1d35e2fSjeremylt   (*rstr)->num_elem = num_elem;
349d1d35e2fSjeremylt   (*rstr)->elem_size = elem_size;
350d1d35e2fSjeremylt   (*rstr)->num_comp = num_comp;
351d1d35e2fSjeremylt   (*rstr)->comp_stride = comp_stride;
352d1d35e2fSjeremylt   (*rstr)->l_size = l_size;
353d1d35e2fSjeremylt   (*rstr)->num_blk = num_elem;
354d1d35e2fSjeremylt   (*rstr)->blk_size = 1;
355d1d35e2fSjeremylt   ierr = ceed->ElemRestrictionCreate(mem_type, copy_mode, offsets, *rstr);
356d979a051Sjeremylt   CeedChk(ierr);
357e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
358d7b241e6Sjeremylt }
359d7b241e6Sjeremylt 
360d7b241e6Sjeremylt /**
361fc0567d9Srezgarshakeri   @brief Create a CeedElemRestriction with orientation sign
362fc0567d9Srezgarshakeri 
363fc0567d9Srezgarshakeri   @param ceed         A Ceed object where the CeedElemRestriction will be created
364fc0567d9Srezgarshakeri   @param num_elem     Number of elements described in the @a offsets array
365fc0567d9Srezgarshakeri   @param elem_size    Size (number of "nodes") per element
366fc0567d9Srezgarshakeri   @param num_comp     Number of field components per interpolation node
367fc0567d9Srezgarshakeri                         (1 for scalar fields)
368fc0567d9Srezgarshakeri   @param comp_stride  Stride between components for the same L-vector "node".
369fc0567d9Srezgarshakeri                         Data for node i, component j, element k can be found in
370fc0567d9Srezgarshakeri                         the L-vector at index
371fc0567d9Srezgarshakeri                         offsets[i + k*elem_size] + j*comp_stride.
372fc0567d9Srezgarshakeri   @param l_size       The size of the L-vector. This vector may be larger than
373fc0567d9Srezgarshakeri                         the elements and fields given by this restriction.
374fc0567d9Srezgarshakeri   @param mem_type     Memory type of the @a offsets array, see CeedMemType
375fc0567d9Srezgarshakeri   @param copy_mode    Copy mode for the @a offsets array, see CeedCopyMode
376fc0567d9Srezgarshakeri   @param offsets      Array of shape [@a num_elem, @a elem_size]. Row i holds the
377fc0567d9Srezgarshakeri                         ordered list of the offsets (into the input CeedVector)
378fc0567d9Srezgarshakeri                         for the unknowns corresponding to element i, where
379fc0567d9Srezgarshakeri                         0 <= i < @a num_elem. All offsets must be in the range
380fc0567d9Srezgarshakeri                         [0, @a l_size - 1].
381fc0567d9Srezgarshakeri   @param orient       Array of shape [@a num_elem, @a elem_size] with bool false
382fc0567d9Srezgarshakeri                         for positively oriented and true to flip the orientation.
383fc0567d9Srezgarshakeri   @param[out] rstr    Address of the variable where the newly created
384fc0567d9Srezgarshakeri                         CeedElemRestriction will be stored
385fc0567d9Srezgarshakeri 
386fc0567d9Srezgarshakeri   @return An error code: 0 - success, otherwise - failure
387fc0567d9Srezgarshakeri 
388fc0567d9Srezgarshakeri   @ref User
389fc0567d9Srezgarshakeri **/
390fc0567d9Srezgarshakeri int CeedElemRestrictionCreateOriented(Ceed ceed, CeedInt num_elem,
391fc0567d9Srezgarshakeri                                       CeedInt elem_size, CeedInt num_comp,
392fc0567d9Srezgarshakeri                                       CeedInt comp_stride, CeedInt l_size,
393fc0567d9Srezgarshakeri                                       CeedMemType mem_type, CeedCopyMode copy_mode,
394fc0567d9Srezgarshakeri                                       const CeedInt *offsets, const bool *orient,
395fc0567d9Srezgarshakeri                                       CeedElemRestriction *rstr) {
396fc0567d9Srezgarshakeri   int ierr;
397fc0567d9Srezgarshakeri 
398*c7745053SRezgar Shakeri   if (!ceed->ElemRestrictionCreateOriented) {
399fc0567d9Srezgarshakeri     Ceed delegate;
400fc0567d9Srezgarshakeri     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
401fc0567d9Srezgarshakeri     CeedChk(ierr);
402fc0567d9Srezgarshakeri 
403fc0567d9Srezgarshakeri     if (!delegate)
404fc0567d9Srezgarshakeri       // LCOV_EXCL_START
405fc0567d9Srezgarshakeri       return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
40661e7462cSRezgar Shakeri                        "Backend does not implement ElemRestrictionCreateOriented");
407fc0567d9Srezgarshakeri     // LCOV_EXCL_STOP
408fc0567d9Srezgarshakeri 
409fc0567d9Srezgarshakeri     ierr = CeedElemRestrictionCreateOriented(delegate, num_elem, elem_size,
410*c7745053SRezgar Shakeri            num_comp, comp_stride, l_size, mem_type, copy_mode, offsets,
4114dd06d33Srezgarshakeri            orient, rstr); CeedChk(ierr);
412fc0567d9Srezgarshakeri     return CEED_ERROR_SUCCESS;
413fc0567d9Srezgarshakeri   }
414fc0567d9Srezgarshakeri 
415fc0567d9Srezgarshakeri   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
416fc0567d9Srezgarshakeri   (*rstr)->ceed = ceed;
417fc0567d9Srezgarshakeri   ierr = CeedReference(ceed); CeedChk(ierr);
418fc0567d9Srezgarshakeri   (*rstr)->ref_count = 1;
419fc0567d9Srezgarshakeri   (*rstr)->num_elem = num_elem;
420fc0567d9Srezgarshakeri   (*rstr)->elem_size = elem_size;
421fc0567d9Srezgarshakeri   (*rstr)->num_comp = num_comp;
422fc0567d9Srezgarshakeri   (*rstr)->comp_stride = comp_stride;
423fc0567d9Srezgarshakeri   (*rstr)->l_size = l_size;
424fc0567d9Srezgarshakeri   (*rstr)->num_blk = num_elem;
425fc0567d9Srezgarshakeri   (*rstr)->blk_size = 1;
4264dd06d33Srezgarshakeri   ierr = ceed->ElemRestrictionCreateOriented(mem_type, copy_mode,
4274dd06d33Srezgarshakeri          offsets, orient, *rstr); CeedChk(ierr);
428fc0567d9Srezgarshakeri   return CEED_ERROR_SUCCESS;
429fc0567d9Srezgarshakeri }
430fc0567d9Srezgarshakeri 
431fc0567d9Srezgarshakeri /**
4327509a596Sjeremylt   @brief Create a strided CeedElemRestriction
433d7b241e6Sjeremylt 
434b11c1e72Sjeremylt   @param ceed       A Ceed object where the CeedElemRestriction will be created
435d1d35e2fSjeremylt   @param num_elem   Number of elements described by the restriction
436d1d35e2fSjeremylt   @param elem_size  Size (number of "nodes") per element
437d1d35e2fSjeremylt   @param num_comp   Number of field components per interpolation "node"
43895bb1877Svaleriabarra                       (1 for scalar fields)
439d1d35e2fSjeremylt   @param l_size     The size of the L-vector. This vector may be larger than
440d979a051Sjeremylt                       the elements and fields given by this restriction.
4417509a596Sjeremylt   @param strides    Array for strides between [nodes, components, elements].
44295e93d34SJeremy L Thompson                       Data for node i, component j, element k can be found in
44395e93d34SJeremy L Thompson                       the L-vector at index
44495e93d34SJeremy L Thompson                       i*strides[0] + j*strides[1] + k*strides[2].
44595e93d34SJeremy L Thompson                       @a CEED_STRIDES_BACKEND may be used with vectors created
44695e93d34SJeremy L Thompson                       by a Ceed backend.
4474ce2993fSjeremylt   @param rstr       Address of the variable where the newly created
448b11c1e72Sjeremylt                       CeedElemRestriction will be stored
449d7b241e6Sjeremylt 
450b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
451dfdf5a53Sjeremylt 
4527a982d89SJeremy L. Thompson   @ref User
453b11c1e72Sjeremylt **/
454d1d35e2fSjeremylt int CeedElemRestrictionCreateStrided(Ceed ceed, CeedInt num_elem,
455d1d35e2fSjeremylt                                      CeedInt elem_size,
456d1d35e2fSjeremylt                                      CeedInt num_comp, CeedInt l_size,
4578621c6c6SJeremy L Thompson                                      const CeedInt strides[3],
458f90c8643Sjeremylt                                      CeedElemRestriction *rstr) {
459d7b241e6Sjeremylt   int ierr;
460d7b241e6Sjeremylt 
4615fe0d4faSjeremylt   if (!ceed->ElemRestrictionCreate) {
4625fe0d4faSjeremylt     Ceed delegate;
463aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
464aefd8378Sjeremylt     CeedChk(ierr);
4655fe0d4faSjeremylt 
4665fe0d4faSjeremylt     if (!delegate)
467c042f62fSJeremy L Thompson       // LCOV_EXCL_START
468e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
469e15f9bd0SJeremy L Thompson                        "Backend does not support ElemRestrictionCreate");
470c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
4715fe0d4faSjeremylt 
472d1d35e2fSjeremylt     ierr = CeedElemRestrictionCreateStrided(delegate, num_elem, elem_size, num_comp,
473d1d35e2fSjeremylt                                             l_size, strides, rstr);
474d979a051Sjeremylt     CeedChk(ierr);
475e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
4765fe0d4faSjeremylt   }
4775fe0d4faSjeremylt 
4784ce2993fSjeremylt   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
4794ce2993fSjeremylt   (*rstr)->ceed = ceed;
4809560d06aSjeremylt   ierr = CeedReference(ceed); CeedChk(ierr);
481d1d35e2fSjeremylt   (*rstr)->ref_count = 1;
482d1d35e2fSjeremylt   (*rstr)->num_elem = num_elem;
483d1d35e2fSjeremylt   (*rstr)->elem_size = elem_size;
484d1d35e2fSjeremylt   (*rstr)->num_comp = num_comp;
485d1d35e2fSjeremylt   (*rstr)->l_size = l_size;
486d1d35e2fSjeremylt   (*rstr)->num_blk = num_elem;
487d1d35e2fSjeremylt   (*rstr)->blk_size = 1;
4887509a596Sjeremylt   ierr = CeedMalloc(3, &(*rstr)->strides); CeedChk(ierr);
4897509a596Sjeremylt   for (int i=0; i<3; i++)
4907509a596Sjeremylt     (*rstr)->strides[i] = strides[i];
4911dfeef1dSjeremylt   ierr = ceed->ElemRestrictionCreate(CEED_MEM_HOST, CEED_OWN_POINTER, NULL,
4921dfeef1dSjeremylt                                      *rstr);
4934b8bea3bSJed Brown   CeedChk(ierr);
494e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
495d7b241e6Sjeremylt }
496d7b241e6Sjeremylt 
497d7b241e6Sjeremylt /**
498b11c1e72Sjeremylt   @brief Create a blocked CeedElemRestriction, typically only called by backends
499d7b241e6Sjeremylt 
500d7b241e6Sjeremylt   @param ceed         A Ceed object where the CeedElemRestriction will be created.
501d1d35e2fSjeremylt   @param num_elem     Number of elements described in the @a offsets array.
502d1d35e2fSjeremylt   @param elem_size    Size (number of unknowns) per element
503d1d35e2fSjeremylt   @param blk_size     Number of elements in a block
504d1d35e2fSjeremylt   @param num_comp     Number of field components per interpolation node
50595bb1877Svaleriabarra                         (1 for scalar fields)
506d1d35e2fSjeremylt   @param comp_stride  Stride between components for the same L-vector "node".
50795e93d34SJeremy L Thompson                         Data for node i, component j, element k can be found in
50895e93d34SJeremy L Thompson                         the L-vector at index
509d1d35e2fSjeremylt                         offsets[i + k*elem_size] + j*comp_stride.
510d1d35e2fSjeremylt   @param l_size       The size of the L-vector. This vector may be larger than
511d979a051Sjeremylt                         the elements and fields given by this restriction.
512d1d35e2fSjeremylt   @param mem_type     Memory type of the @a offsets array, see CeedMemType
513d1d35e2fSjeremylt   @param copy_mode    Copy mode for the @a offsets array, see CeedCopyMode
514d1d35e2fSjeremylt   @param offsets      Array of shape [@a num_elem, @a elem_size]. Row i holds the
515d979a051Sjeremylt                         ordered list of the offsets (into the input CeedVector)
5168795c945Sjeremylt                         for the unknowns corresponding to element i, where
517d1d35e2fSjeremylt                         0 <= i < @a num_elem. All offsets must be in the range
518d1d35e2fSjeremylt                         [0, @a l_size - 1]. The backend will permute and pad this
5198795c945Sjeremylt                         array to the desired ordering for the blocksize, which is
5208795c945Sjeremylt                         typically given by the backend. The default reordering is
5218795c945Sjeremylt                         to interlace elements.
5224ce2993fSjeremylt   @param rstr         Address of the variable where the newly created
523b11c1e72Sjeremylt                         CeedElemRestriction will be stored
524d7b241e6Sjeremylt 
525b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
526dfdf5a53Sjeremylt 
5277a982d89SJeremy L. Thompson   @ref Backend
528b11c1e72Sjeremylt  **/
529d1d35e2fSjeremylt int CeedElemRestrictionCreateBlocked(Ceed ceed, CeedInt num_elem,
530d1d35e2fSjeremylt                                      CeedInt elem_size,
531d1d35e2fSjeremylt                                      CeedInt blk_size, CeedInt num_comp,
532d1d35e2fSjeremylt                                      CeedInt comp_stride, CeedInt l_size,
533d1d35e2fSjeremylt                                      CeedMemType mem_type, CeedCopyMode copy_mode,
534d979a051Sjeremylt                                      const CeedInt *offsets,
5354ce2993fSjeremylt                                      CeedElemRestriction *rstr) {
536d7b241e6Sjeremylt   int ierr;
537d1d35e2fSjeremylt   CeedInt *blk_offsets;
538d1d35e2fSjeremylt   CeedInt num_blk = (num_elem / blk_size) + !!(num_elem % blk_size);
539d7b241e6Sjeremylt 
5405fe0d4faSjeremylt   if (!ceed->ElemRestrictionCreateBlocked) {
5415fe0d4faSjeremylt     Ceed delegate;
542aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
543aefd8378Sjeremylt     CeedChk(ierr);
5445fe0d4faSjeremylt 
5455fe0d4faSjeremylt     if (!delegate)
546c042f62fSJeremy L Thompson       // LCOV_EXCL_START
547e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support "
5481d102b48SJeremy L Thompson                        "ElemRestrictionCreateBlocked");
549c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
5505fe0d4faSjeremylt 
551d1d35e2fSjeremylt     ierr = CeedElemRestrictionCreateBlocked(delegate, num_elem, elem_size, blk_size,
552d1d35e2fSjeremylt                                             num_comp, comp_stride, l_size, mem_type,
553d1d35e2fSjeremylt                                             copy_mode, offsets, rstr);
554d979a051Sjeremylt     CeedChk(ierr);
555e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
5565fe0d4faSjeremylt   }
557d7b241e6Sjeremylt 
5584ce2993fSjeremylt   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
559d7b241e6Sjeremylt 
560d1d35e2fSjeremylt   ierr = CeedCalloc(num_blk*blk_size*elem_size, &blk_offsets); CeedChk(ierr);
561d1d35e2fSjeremylt   ierr = CeedPermutePadOffsets(offsets, blk_offsets, num_blk, num_elem, blk_size,
562d1d35e2fSjeremylt                                elem_size); CeedChk(ierr);
563d7b241e6Sjeremylt 
5644ce2993fSjeremylt   (*rstr)->ceed = ceed;
5659560d06aSjeremylt   ierr = CeedReference(ceed); CeedChk(ierr);
566d1d35e2fSjeremylt   (*rstr)->ref_count = 1;
567d1d35e2fSjeremylt   (*rstr)->num_elem = num_elem;
568d1d35e2fSjeremylt   (*rstr)->elem_size = elem_size;
569d1d35e2fSjeremylt   (*rstr)->num_comp = num_comp;
570d1d35e2fSjeremylt   (*rstr)->comp_stride = comp_stride;
571d1d35e2fSjeremylt   (*rstr)->l_size = l_size;
572d1d35e2fSjeremylt   (*rstr)->num_blk = num_blk;
573d1d35e2fSjeremylt   (*rstr)->blk_size = blk_size;
574667bc5fcSjeremylt   ierr = ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER,
575d1d35e2fSjeremylt          (const CeedInt *) blk_offsets, *rstr); CeedChk(ierr);
576d1d35e2fSjeremylt   if (copy_mode == CEED_OWN_POINTER) {
577d979a051Sjeremylt     ierr = CeedFree(&offsets); CeedChk(ierr);
5781d102b48SJeremy L Thompson   }
579e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
580d7b241e6Sjeremylt }
581d7b241e6Sjeremylt 
582b11c1e72Sjeremylt /**
5837509a596Sjeremylt   @brief Create a blocked strided CeedElemRestriction
5847509a596Sjeremylt 
5857509a596Sjeremylt   @param ceed       A Ceed object where the CeedElemRestriction will be created
586d1d35e2fSjeremylt   @param num_elem   Number of elements described by the restriction
587d1d35e2fSjeremylt   @param elem_size  Size (number of "nodes") per element
588d1d35e2fSjeremylt   @param blk_size   Number of elements in a block
589d1d35e2fSjeremylt   @param num_comp   Number of field components per interpolation node
5907509a596Sjeremylt                       (1 for scalar fields)
591d1d35e2fSjeremylt   @param l_size     The size of the L-vector. This vector may be larger than
592d979a051Sjeremylt                       the elements and fields given by this restriction.
5937509a596Sjeremylt   @param strides    Array for strides between [nodes, components, elements].
59495e93d34SJeremy L Thompson                       Data for node i, component j, element k can be found in
59595e93d34SJeremy L Thompson                       the L-vector at index
59695e93d34SJeremy L Thompson                       i*strides[0] + j*strides[1] + k*strides[2].
59795e93d34SJeremy L Thompson                       @a CEED_STRIDES_BACKEND may be used with vectors created
59895e93d34SJeremy L Thompson                       by a Ceed backend.
5997509a596Sjeremylt   @param rstr       Address of the variable where the newly created
6007509a596Sjeremylt                       CeedElemRestriction will be stored
6017509a596Sjeremylt 
6027509a596Sjeremylt   @return An error code: 0 - success, otherwise - failure
6037509a596Sjeremylt 
6047a982d89SJeremy L. Thompson   @ref User
6057509a596Sjeremylt **/
606d1d35e2fSjeremylt int CeedElemRestrictionCreateBlockedStrided(Ceed ceed, CeedInt num_elem,
607d1d35e2fSjeremylt     CeedInt elem_size, CeedInt blk_size, CeedInt num_comp, CeedInt l_size,
6088621c6c6SJeremy L Thompson     const CeedInt strides[3], CeedElemRestriction *rstr) {
6097509a596Sjeremylt   int ierr;
610d1d35e2fSjeremylt   CeedInt num_blk = (num_elem / blk_size) + !!(num_elem % blk_size);
6117509a596Sjeremylt 
6127509a596Sjeremylt   if (!ceed->ElemRestrictionCreateBlocked) {
6137509a596Sjeremylt     Ceed delegate;
6147509a596Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
6157509a596Sjeremylt     CeedChk(ierr);
6167509a596Sjeremylt 
6177509a596Sjeremylt     if (!delegate)
6187509a596Sjeremylt       // LCOV_EXCL_START
619e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support "
6207509a596Sjeremylt                        "ElemRestrictionCreateBlocked");
6217509a596Sjeremylt     // LCOV_EXCL_STOP
6227509a596Sjeremylt 
623d1d35e2fSjeremylt     ierr = CeedElemRestrictionCreateBlockedStrided(delegate, num_elem, elem_size,
624d1d35e2fSjeremylt            blk_size, num_comp, l_size, strides, rstr); CeedChk(ierr);
625e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
6267509a596Sjeremylt   }
6277509a596Sjeremylt 
6287509a596Sjeremylt   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
6297509a596Sjeremylt 
6307509a596Sjeremylt   (*rstr)->ceed = ceed;
6319560d06aSjeremylt   ierr = CeedReference(ceed); CeedChk(ierr);
632d1d35e2fSjeremylt   (*rstr)->ref_count = 1;
633d1d35e2fSjeremylt   (*rstr)->num_elem = num_elem;
634d1d35e2fSjeremylt   (*rstr)->elem_size = elem_size;
635d1d35e2fSjeremylt   (*rstr)->num_comp = num_comp;
636d1d35e2fSjeremylt   (*rstr)->l_size = l_size;
637d1d35e2fSjeremylt   (*rstr)->num_blk = num_blk;
638d1d35e2fSjeremylt   (*rstr)->blk_size = blk_size;
6397509a596Sjeremylt   ierr = CeedMalloc(3, &(*rstr)->strides); CeedChk(ierr);
6407509a596Sjeremylt   for (int i=0; i<3; i++)
6417509a596Sjeremylt     (*rstr)->strides[i] = strides[i];
6427509a596Sjeremylt   ierr = ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER,
6437509a596Sjeremylt          NULL, *rstr); CeedChk(ierr);
644e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6457509a596Sjeremylt }
6467509a596Sjeremylt 
6477509a596Sjeremylt /**
6489560d06aSjeremylt   @brief Copy the pointer to a CeedElemRestriction. Both pointers should
6499560d06aSjeremylt            be destroyed with `CeedElemRestrictionDestroy()`;
6509560d06aSjeremylt            Note: If `*rstr_copy` is non-NULL, then it is assumed that
6519560d06aSjeremylt            `*rstr_copy` is a pointer to a CeedElemRestriction. This
6529560d06aSjeremylt            CeedElemRestriction will be destroyed if `*rstr_copy` is the
6539560d06aSjeremylt            only reference to this CeedElemRestriction.
6549560d06aSjeremylt 
6559560d06aSjeremylt   @param rstr            CeedElemRestriction to copy reference to
6569560d06aSjeremylt   @param[out] rstr_copy  Variable to store copied reference
6579560d06aSjeremylt 
6589560d06aSjeremylt   @return An error code: 0 - success, otherwise - failure
6599560d06aSjeremylt 
6609560d06aSjeremylt   @ref User
6619560d06aSjeremylt **/
6629560d06aSjeremylt int CeedElemRestrictionReferenceCopy(CeedElemRestriction rstr,
6639560d06aSjeremylt                                      CeedElemRestriction *rstr_copy) {
6649560d06aSjeremylt   int ierr;
6659560d06aSjeremylt 
6669560d06aSjeremylt   ierr = CeedElemRestrictionReference(rstr); CeedChk(ierr);
6679560d06aSjeremylt   ierr = CeedElemRestrictionDestroy(rstr_copy); CeedChk(ierr);
6689560d06aSjeremylt   *rstr_copy = rstr;
6699560d06aSjeremylt   return CEED_ERROR_SUCCESS;
6709560d06aSjeremylt }
6719560d06aSjeremylt 
6729560d06aSjeremylt /**
673b11c1e72Sjeremylt   @brief Create CeedVectors associated with a CeedElemRestriction
674b11c1e72Sjeremylt 
6754ce2993fSjeremylt   @param rstr   CeedElemRestriction
676d1d35e2fSjeremylt   @param l_vec  The address of the L-vector to be created, or NULL
677d1d35e2fSjeremylt   @param e_vec  The address of the E-vector to be created, or NULL
678b11c1e72Sjeremylt 
679b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
680dfdf5a53Sjeremylt 
6817a982d89SJeremy L. Thompson   @ref User
682b11c1e72Sjeremylt **/
683d1d35e2fSjeremylt int CeedElemRestrictionCreateVector(CeedElemRestriction rstr, CeedVector *l_vec,
684d1d35e2fSjeremylt                                     CeedVector *e_vec) {
685d7b241e6Sjeremylt   int ierr;
686d1d35e2fSjeremylt   CeedInt e_size, l_size;
687d1d35e2fSjeremylt   l_size = rstr->l_size;
688d1d35e2fSjeremylt   e_size = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp;
689d1d35e2fSjeremylt   if (l_vec) {
690d1d35e2fSjeremylt     ierr = CeedVectorCreate(rstr->ceed, l_size, l_vec); CeedChk(ierr);
691d7b241e6Sjeremylt   }
692d1d35e2fSjeremylt   if (e_vec) {
693d1d35e2fSjeremylt     ierr = CeedVectorCreate(rstr->ceed, e_size, e_vec); CeedChk(ierr);
694d7b241e6Sjeremylt   }
695e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
696d7b241e6Sjeremylt }
697d7b241e6Sjeremylt 
698d7b241e6Sjeremylt /**
699d9e1f99aSValeria Barra   @brief Restrict an L-vector to an E-vector or apply its transpose
700d7b241e6Sjeremylt 
7014ce2993fSjeremylt   @param rstr    CeedElemRestriction
702d1d35e2fSjeremylt   @param t_mode  Apply restriction or transpose
703d1d35e2fSjeremylt   @param u       Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE)
704d1d35e2fSjeremylt   @param ru      Output vector (of shape [@a num_elem * @a elem_size] when
705d1d35e2fSjeremylt                    t_mode=@ref CEED_NOTRANSPOSE). Ordering of the e-vector is decided
7067aaeacdcSjeremylt                    by the backend.
7074cc79fe7SJed Brown   @param request Request or @ref CEED_REQUEST_IMMEDIATE
708b11c1e72Sjeremylt 
709b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
710dfdf5a53Sjeremylt 
7117a982d89SJeremy L. Thompson   @ref User
712b11c1e72Sjeremylt **/
713d1d35e2fSjeremylt int CeedElemRestrictionApply(CeedElemRestriction rstr, CeedTransposeMode t_mode,
714a8d32208Sjeremylt                              CeedVector u, CeedVector ru,
715a8d32208Sjeremylt                              CeedRequest *request) {
716d7b241e6Sjeremylt   CeedInt m, n;
717d7b241e6Sjeremylt   int ierr;
718d7b241e6Sjeremylt 
719d1d35e2fSjeremylt   if (t_mode == CEED_NOTRANSPOSE) {
720d1d35e2fSjeremylt     m = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp;
721d1d35e2fSjeremylt     n = rstr->l_size;
722d7b241e6Sjeremylt   } else {
723d1d35e2fSjeremylt     m = rstr->l_size;
724d1d35e2fSjeremylt     n = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp;
725d7b241e6Sjeremylt   }
726d7b241e6Sjeremylt   if (n != u->length)
727c042f62fSJeremy L Thompson     // LCOV_EXCL_START
728e15f9bd0SJeremy L Thompson     return CeedError(rstr->ceed, CEED_ERROR_DIMENSION,
729e15f9bd0SJeremy L Thompson                      "Input vector size %d not compatible with "
7301d102b48SJeremy L Thompson                      "element restriction (%d, %d)", u->length, m, n);
731c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
732a8d32208Sjeremylt   if (m != ru->length)
733c042f62fSJeremy L Thompson     // LCOV_EXCL_START
734e15f9bd0SJeremy L Thompson     return CeedError(rstr->ceed, CEED_ERROR_DIMENSION,
735e15f9bd0SJeremy L Thompson                      "Output vector size %d not compatible with "
736a8d32208Sjeremylt                      "element restriction (%d, %d)", ru->length, m, n);
737c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
738d1d35e2fSjeremylt   ierr = rstr->Apply(rstr, t_mode, u, ru, request); CeedChk(ierr);
739e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
740d7b241e6Sjeremylt }
741d7b241e6Sjeremylt 
742d7b241e6Sjeremylt /**
743d9e1f99aSValeria Barra   @brief Restrict an L-vector to a block of an E-vector or apply its transpose
744be9261b7Sjeremylt 
745be9261b7Sjeremylt   @param rstr    CeedElemRestriction
7461f37b403Sjeremylt   @param block   Block number to restrict to/from, i.e. block=0 will handle
747d1d35e2fSjeremylt                    elements [0 : blk_size] and block=3 will handle elements
748d1d35e2fSjeremylt                    [3*blk_size : 4*blk_size]
749d1d35e2fSjeremylt   @param t_mode  Apply restriction or transpose
750d1d35e2fSjeremylt   @param u       Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE)
751d1d35e2fSjeremylt   @param ru      Output vector (of shape [@a blk_size * @a elem_size] when
752d1d35e2fSjeremylt                    t_mode=@ref CEED_NOTRANSPOSE). Ordering of the e-vector is decided
7537aaeacdcSjeremylt                    by the backend.
7544cc79fe7SJed Brown   @param request Request or @ref CEED_REQUEST_IMMEDIATE
755be9261b7Sjeremylt 
756be9261b7Sjeremylt   @return An error code: 0 - success, otherwise - failure
757be9261b7Sjeremylt 
7587a982d89SJeremy L. Thompson   @ref Backend
759be9261b7Sjeremylt **/
760be9261b7Sjeremylt int CeedElemRestrictionApplyBlock(CeedElemRestriction rstr, CeedInt block,
761d1d35e2fSjeremylt                                   CeedTransposeMode t_mode, CeedVector u,
762a8d32208Sjeremylt                                   CeedVector ru, CeedRequest *request) {
763be9261b7Sjeremylt   CeedInt m, n;
764be9261b7Sjeremylt   int ierr;
765be9261b7Sjeremylt 
766d1d35e2fSjeremylt   if (t_mode == CEED_NOTRANSPOSE) {
767d1d35e2fSjeremylt     m = rstr->blk_size * rstr->elem_size * rstr->num_comp;
768d1d35e2fSjeremylt     n = rstr->l_size;
769be9261b7Sjeremylt   } else {
770d1d35e2fSjeremylt     m = rstr->l_size;
771d1d35e2fSjeremylt     n = rstr->blk_size * rstr->elem_size * rstr->num_comp;
772be9261b7Sjeremylt   }
773be9261b7Sjeremylt   if (n != u->length)
774c042f62fSJeremy L Thompson     // LCOV_EXCL_START
775e15f9bd0SJeremy L Thompson     return CeedError(rstr->ceed, CEED_ERROR_DIMENSION,
776e15f9bd0SJeremy L Thompson                      "Input vector size %d not compatible with "
7771d102b48SJeremy L Thompson                      "element restriction (%d, %d)", u->length, m, n);
778c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
779a8d32208Sjeremylt   if (m != ru->length)
780c042f62fSJeremy L Thompson     // LCOV_EXCL_START
781e15f9bd0SJeremy L Thompson     return CeedError(rstr->ceed, CEED_ERROR_DIMENSION,
782e15f9bd0SJeremy L Thompson                      "Output vector size %d not compatible with "
783a8d32208Sjeremylt                      "element restriction (%d, %d)", ru->length, m, n);
784c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
785d1d35e2fSjeremylt   if (rstr->blk_size*block > rstr->num_elem)
786c042f62fSJeremy L Thompson     // LCOV_EXCL_START
787e15f9bd0SJeremy L Thompson     return CeedError(rstr->ceed, CEED_ERROR_DIMENSION,
788e15f9bd0SJeremy L Thompson                      "Cannot retrieve block %d, element %d > "
789d1d35e2fSjeremylt                      "total elements %d", block, rstr->blk_size*block,
790d1d35e2fSjeremylt                      rstr->num_elem);
791c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
792d1d35e2fSjeremylt   ierr = rstr->ApplyBlock(rstr, block, t_mode, u, ru, request);
793be9261b7Sjeremylt   CeedChk(ierr);
794e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
795be9261b7Sjeremylt }
796be9261b7Sjeremylt 
797be9261b7Sjeremylt /**
798b7c9bbdaSJeremy L Thompson   @brief Get the Ceed associated with a CeedElemRestriction
799b7c9bbdaSJeremy L Thompson 
800b7c9bbdaSJeremy L Thompson   @param rstr       CeedElemRestriction
801b7c9bbdaSJeremy L Thompson   @param[out] ceed  Variable to store Ceed
802b7c9bbdaSJeremy L Thompson 
803b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
804b7c9bbdaSJeremy L Thompson 
805b7c9bbdaSJeremy L Thompson   @ref Advanced
806b7c9bbdaSJeremy L Thompson **/
807b7c9bbdaSJeremy L Thompson int CeedElemRestrictionGetCeed(CeedElemRestriction rstr, Ceed *ceed) {
808b7c9bbdaSJeremy L Thompson   *ceed = rstr->ceed;
809b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
810b7c9bbdaSJeremy L Thompson }
811b7c9bbdaSJeremy L Thompson 
812b7c9bbdaSJeremy L Thompson /**
813d979a051Sjeremylt   @brief Get the L-vector component stride
814a681ae63Sjeremylt 
815a681ae63Sjeremylt   @param rstr              CeedElemRestriction
816d1d35e2fSjeremylt   @param[out] comp_stride  Variable to store component stride
817a681ae63Sjeremylt 
818a681ae63Sjeremylt   @return An error code: 0 - success, otherwise - failure
819a681ae63Sjeremylt 
820b7c9bbdaSJeremy L Thompson   @ref Advanced
821a681ae63Sjeremylt **/
822d979a051Sjeremylt int CeedElemRestrictionGetCompStride(CeedElemRestriction rstr,
823d1d35e2fSjeremylt                                      CeedInt *comp_stride) {
824d1d35e2fSjeremylt   *comp_stride = rstr->comp_stride;
825e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
826a681ae63Sjeremylt }
827a681ae63Sjeremylt 
828a681ae63Sjeremylt /**
829a681ae63Sjeremylt   @brief Get the total number of elements in the range of a CeedElemRestriction
830a681ae63Sjeremylt 
831a681ae63Sjeremylt   @param rstr           CeedElemRestriction
832d1d35e2fSjeremylt   @param[out] num_elem  Variable to store number of elements
833a681ae63Sjeremylt 
834a681ae63Sjeremylt   @return An error code: 0 - success, otherwise - failure
835a681ae63Sjeremylt 
836b7c9bbdaSJeremy L Thompson   @ref Advanced
837a681ae63Sjeremylt **/
838a681ae63Sjeremylt int CeedElemRestrictionGetNumElements(CeedElemRestriction rstr,
839d1d35e2fSjeremylt                                       CeedInt *num_elem) {
840d1d35e2fSjeremylt   *num_elem = rstr->num_elem;
841e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
842a681ae63Sjeremylt }
843a681ae63Sjeremylt 
844a681ae63Sjeremylt /**
845a681ae63Sjeremylt   @brief Get the size of elements in the CeedElemRestriction
846a681ae63Sjeremylt 
847a681ae63Sjeremylt   @param rstr            CeedElemRestriction
848d1d35e2fSjeremylt   @param[out] elem_size  Variable to store size of elements
849a681ae63Sjeremylt 
850a681ae63Sjeremylt   @return An error code: 0 - success, otherwise - failure
851a681ae63Sjeremylt 
852b7c9bbdaSJeremy L Thompson   @ref Advanced
853a681ae63Sjeremylt **/
854a681ae63Sjeremylt int CeedElemRestrictionGetElementSize(CeedElemRestriction rstr,
855d1d35e2fSjeremylt                                       CeedInt *elem_size) {
856d1d35e2fSjeremylt   *elem_size = rstr->elem_size;
857e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
858a681ae63Sjeremylt }
859a681ae63Sjeremylt 
860a681ae63Sjeremylt /**
861d979a051Sjeremylt   @brief Get the size of the l-vector for a CeedElemRestriction
862a681ae63Sjeremylt 
863a681ae63Sjeremylt   @param rstr         CeedElemRestriction
864d1d35e2fSjeremylt   @param[out] l_size  Variable to store number of nodes
865a681ae63Sjeremylt 
866a681ae63Sjeremylt   @return An error code: 0 - success, otherwise - failure
867a681ae63Sjeremylt 
868b7c9bbdaSJeremy L Thompson   @ref Advanced
869a681ae63Sjeremylt **/
870d979a051Sjeremylt int CeedElemRestrictionGetLVectorSize(CeedElemRestriction rstr,
871d1d35e2fSjeremylt                                       CeedInt *l_size) {
872d1d35e2fSjeremylt   *l_size = rstr->l_size;
873e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
874a681ae63Sjeremylt }
875a681ae63Sjeremylt 
876a681ae63Sjeremylt /**
877a681ae63Sjeremylt   @brief Get the number of components in the elements of a
878a681ae63Sjeremylt          CeedElemRestriction
879a681ae63Sjeremylt 
880a681ae63Sjeremylt   @param rstr           CeedElemRestriction
881d1d35e2fSjeremylt   @param[out] num_comp  Variable to store number of components
882a681ae63Sjeremylt 
883a681ae63Sjeremylt   @return An error code: 0 - success, otherwise - failure
884a681ae63Sjeremylt 
885b7c9bbdaSJeremy L Thompson   @ref Advanced
886a681ae63Sjeremylt **/
887a681ae63Sjeremylt int CeedElemRestrictionGetNumComponents(CeedElemRestriction rstr,
888d1d35e2fSjeremylt                                         CeedInt *num_comp) {
889d1d35e2fSjeremylt   *num_comp = rstr->num_comp;
890e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
891a681ae63Sjeremylt }
892a681ae63Sjeremylt 
893a681ae63Sjeremylt /**
894a681ae63Sjeremylt   @brief Get the number of blocks in a CeedElemRestriction
895a681ae63Sjeremylt 
896a681ae63Sjeremylt   @param rstr            CeedElemRestriction
897d1d35e2fSjeremylt   @param[out] num_block  Variable to store number of blocks
898a681ae63Sjeremylt 
899a681ae63Sjeremylt   @return An error code: 0 - success, otherwise - failure
900a681ae63Sjeremylt 
901b7c9bbdaSJeremy L Thompson   @ref Advanced
902a681ae63Sjeremylt **/
903a681ae63Sjeremylt int CeedElemRestrictionGetNumBlocks(CeedElemRestriction rstr,
904d1d35e2fSjeremylt                                     CeedInt *num_block) {
905d1d35e2fSjeremylt   *num_block = rstr->num_blk;
906e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
907a681ae63Sjeremylt }
908a681ae63Sjeremylt 
909a681ae63Sjeremylt /**
910a681ae63Sjeremylt   @brief Get the size of blocks in the CeedElemRestriction
911a681ae63Sjeremylt 
912a681ae63Sjeremylt   @param rstr           CeedElemRestriction
913d1d35e2fSjeremylt   @param[out] blk_size  Variable to store size of blocks
914a681ae63Sjeremylt 
915a681ae63Sjeremylt   @return An error code: 0 - success, otherwise - failure
916a681ae63Sjeremylt 
917b7c9bbdaSJeremy L Thompson   @ref Advanced
918a681ae63Sjeremylt **/
919a681ae63Sjeremylt int CeedElemRestrictionGetBlockSize(CeedElemRestriction rstr,
920d1d35e2fSjeremylt                                     CeedInt *blk_size) {
921d1d35e2fSjeremylt   *blk_size = rstr->blk_size;
922e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
923a681ae63Sjeremylt }
924a681ae63Sjeremylt 
925a681ae63Sjeremylt /**
926d9e1f99aSValeria Barra   @brief Get the multiplicity of nodes in a CeedElemRestriction
9271469ee4dSjeremylt 
9281469ee4dSjeremylt   @param rstr       CeedElemRestriction
929d1d35e2fSjeremylt   @param[out] mult  Vector to store multiplicity (of size l_size)
9301469ee4dSjeremylt 
9311469ee4dSjeremylt   @return An error code: 0 - success, otherwise - failure
9321469ee4dSjeremylt 
9337a982d89SJeremy L. Thompson   @ref User
9341469ee4dSjeremylt **/
9351469ee4dSjeremylt int CeedElemRestrictionGetMultiplicity(CeedElemRestriction rstr,
9361469ee4dSjeremylt                                        CeedVector mult) {
9371469ee4dSjeremylt   int ierr;
938d1d35e2fSjeremylt   CeedVector e_vec;
9391469ee4dSjeremylt 
94025509ebbSRezgar Shakeri   // Create e_vec to hold intermediate computation in E^T (E 1)
941d1d35e2fSjeremylt   ierr = CeedElemRestrictionCreateVector(rstr, NULL, &e_vec); CeedChk(ierr);
9421469ee4dSjeremylt 
94325509ebbSRezgar Shakeri   // Compute e_vec = E * 1
94425509ebbSRezgar Shakeri   ierr = CeedVectorSetValue(mult, 1.0); CeedChk(ierr);
94525509ebbSRezgar Shakeri   ierr = CeedElemRestrictionApply(rstr, CEED_NOTRANSPOSE, mult, e_vec,
94625509ebbSRezgar Shakeri                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
94725509ebbSRezgar Shakeri   // Compute multiplicity, mult = E^T * e_vec = E^T (E 1)
94825509ebbSRezgar Shakeri   ierr = CeedVectorSetValue(mult, 0.0); CeedChk(ierr);
949d1d35e2fSjeremylt   ierr = CeedElemRestrictionApply(rstr, CEED_TRANSPOSE, e_vec, mult,
950efc78312Sjeremylt                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
9511469ee4dSjeremylt   // Cleanup
952d1d35e2fSjeremylt   ierr = CeedVectorDestroy(&e_vec); CeedChk(ierr);
953e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
9541469ee4dSjeremylt }
9551469ee4dSjeremylt 
9561469ee4dSjeremylt /**
957f02ca4a2SJed Brown   @brief View a CeedElemRestriction
958f02ca4a2SJed Brown 
959f02ca4a2SJed Brown   @param[in] rstr    CeedElemRestriction to view
960f02ca4a2SJed Brown   @param[in] stream  Stream to write; typically stdout/stderr or a file
961f02ca4a2SJed Brown 
962f02ca4a2SJed Brown   @return Error code: 0 - success, otherwise - failure
963f02ca4a2SJed Brown 
9647a982d89SJeremy L. Thompson   @ref User
965f02ca4a2SJed Brown **/
966f02ca4a2SJed Brown int CeedElemRestrictionView(CeedElemRestriction rstr, FILE *stream) {
9677509a596Sjeremylt   char stridesstr[500];
9687509a596Sjeremylt   if (rstr->strides)
9697509a596Sjeremylt     sprintf(stridesstr, "[%d, %d, %d]", rstr->strides[0], rstr->strides[1],
9707509a596Sjeremylt             rstr->strides[2]);
971d979a051Sjeremylt   else
972d1d35e2fSjeremylt     sprintf(stridesstr, "%d", rstr->comp_stride);
9737509a596Sjeremylt 
9740036de2cSjeremylt   fprintf(stream, "%sCeedElemRestriction from (%d, %d) to %d elements with %d "
975d1d35e2fSjeremylt           "nodes each and %s %s\n", rstr->blk_size > 1 ? "Blocked " : "",
976d1d35e2fSjeremylt           rstr->l_size, rstr->num_comp, rstr->num_elem, rstr->elem_size,
977d979a051Sjeremylt           rstr->strides ? "strides" : "component stride", stridesstr);
978e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
979f02ca4a2SJed Brown }
980f02ca4a2SJed Brown 
981f02ca4a2SJed Brown /**
982b11c1e72Sjeremylt   @brief Destroy a CeedElemRestriction
983b11c1e72Sjeremylt 
9844ce2993fSjeremylt   @param rstr  CeedElemRestriction to destroy
985b11c1e72Sjeremylt 
986b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
987dfdf5a53Sjeremylt 
9887a982d89SJeremy L. Thompson   @ref User
989b11c1e72Sjeremylt **/
9904ce2993fSjeremylt int CeedElemRestrictionDestroy(CeedElemRestriction *rstr) {
991d7b241e6Sjeremylt   int ierr;
992d7b241e6Sjeremylt 
993d1d35e2fSjeremylt   if (!*rstr || --(*rstr)->ref_count > 0) return CEED_ERROR_SUCCESS;
994d1d35e2fSjeremylt   if ((*rstr)->num_readers)
9958229195eSjeremylt     // LCOV_EXCL_START
996e15f9bd0SJeremy L Thompson     return CeedError((*rstr)->ceed, CEED_ERROR_ACCESS,
997e15f9bd0SJeremy L Thompson                      "Cannot destroy CeedElemRestriction, "
998430758c8SJeremy L Thompson                      "a process has read access to the offset data");
9998229195eSjeremylt   // LCOV_EXCL_STOP
10004ce2993fSjeremylt   if ((*rstr)->Destroy) {
10014ce2993fSjeremylt     ierr = (*rstr)->Destroy(*rstr); CeedChk(ierr);
1002d7b241e6Sjeremylt   }
10037509a596Sjeremylt   ierr = CeedFree(&(*rstr)->strides); CeedChk(ierr);
10044ce2993fSjeremylt   ierr = CeedDestroy(&(*rstr)->ceed); CeedChk(ierr);
10054ce2993fSjeremylt   ierr = CeedFree(rstr); CeedChk(ierr);
1006e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1007d7b241e6Sjeremylt }
1008d7b241e6Sjeremylt 
1009d7b241e6Sjeremylt /// @}
1010