xref: /libCEED/rust/libceed-sys/c-src/interface/ceed-elemrestriction.c (revision 61e7462c3a07c3c6a5221ea9e89d0c3cd40e49e5)
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 
398fc0567d9Srezgarshakeri   if (!ceed->ElemRestrictionCreate) {
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,
406*61e7462cSRezgar Shakeri                        "Backend does not implement ElemRestrictionCreateOriented");
407fc0567d9Srezgarshakeri     // LCOV_EXCL_STOP
408fc0567d9Srezgarshakeri 
409fc0567d9Srezgarshakeri     ierr = CeedElemRestrictionCreateOriented(delegate, num_elem, elem_size,
4104dd06d33Srezgarshakeri            num_comp, comp_stride, l_size,
4114dd06d33Srezgarshakeri            mem_type, copy_mode, offsets,
4124dd06d33Srezgarshakeri            orient, rstr); CeedChk(ierr);
413fc0567d9Srezgarshakeri     return CEED_ERROR_SUCCESS;
414fc0567d9Srezgarshakeri   }
415fc0567d9Srezgarshakeri 
416fc0567d9Srezgarshakeri   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
417fc0567d9Srezgarshakeri   (*rstr)->ceed = ceed;
418fc0567d9Srezgarshakeri   ierr = CeedReference(ceed); CeedChk(ierr);
419fc0567d9Srezgarshakeri   (*rstr)->ref_count = 1;
420fc0567d9Srezgarshakeri   (*rstr)->num_elem = num_elem;
421fc0567d9Srezgarshakeri   (*rstr)->elem_size = elem_size;
422fc0567d9Srezgarshakeri   (*rstr)->num_comp = num_comp;
423fc0567d9Srezgarshakeri   (*rstr)->comp_stride = comp_stride;
424fc0567d9Srezgarshakeri   (*rstr)->l_size = l_size;
425fc0567d9Srezgarshakeri   (*rstr)->num_blk = num_elem;
426fc0567d9Srezgarshakeri   (*rstr)->blk_size = 1;
4274dd06d33Srezgarshakeri   ierr = ceed->ElemRestrictionCreateOriented(mem_type, copy_mode,
4284dd06d33Srezgarshakeri          offsets, orient, *rstr); CeedChk(ierr);
429fc0567d9Srezgarshakeri   return CEED_ERROR_SUCCESS;
430fc0567d9Srezgarshakeri }
431fc0567d9Srezgarshakeri 
432fc0567d9Srezgarshakeri /**
4337509a596Sjeremylt   @brief Create a strided CeedElemRestriction
434d7b241e6Sjeremylt 
435b11c1e72Sjeremylt   @param ceed       A Ceed object where the CeedElemRestriction will be created
436d1d35e2fSjeremylt   @param num_elem   Number of elements described by the restriction
437d1d35e2fSjeremylt   @param elem_size  Size (number of "nodes") per element
438d1d35e2fSjeremylt   @param num_comp   Number of field components per interpolation "node"
43995bb1877Svaleriabarra                       (1 for scalar fields)
440d1d35e2fSjeremylt   @param l_size     The size of the L-vector. This vector may be larger than
441d979a051Sjeremylt                       the elements and fields given by this restriction.
4427509a596Sjeremylt   @param strides    Array for strides between [nodes, components, elements].
44395e93d34SJeremy L Thompson                       Data for node i, component j, element k can be found in
44495e93d34SJeremy L Thompson                       the L-vector at index
44595e93d34SJeremy L Thompson                       i*strides[0] + j*strides[1] + k*strides[2].
44695e93d34SJeremy L Thompson                       @a CEED_STRIDES_BACKEND may be used with vectors created
44795e93d34SJeremy L Thompson                       by a Ceed backend.
4484ce2993fSjeremylt   @param rstr       Address of the variable where the newly created
449b11c1e72Sjeremylt                       CeedElemRestriction will be stored
450d7b241e6Sjeremylt 
451b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
452dfdf5a53Sjeremylt 
4537a982d89SJeremy L. Thompson   @ref User
454b11c1e72Sjeremylt **/
455d1d35e2fSjeremylt int CeedElemRestrictionCreateStrided(Ceed ceed, CeedInt num_elem,
456d1d35e2fSjeremylt                                      CeedInt elem_size,
457d1d35e2fSjeremylt                                      CeedInt num_comp, CeedInt l_size,
4588621c6c6SJeremy L Thompson                                      const CeedInt strides[3],
459f90c8643Sjeremylt                                      CeedElemRestriction *rstr) {
460d7b241e6Sjeremylt   int ierr;
461d7b241e6Sjeremylt 
4625fe0d4faSjeremylt   if (!ceed->ElemRestrictionCreate) {
4635fe0d4faSjeremylt     Ceed delegate;
464aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
465aefd8378Sjeremylt     CeedChk(ierr);
4665fe0d4faSjeremylt 
4675fe0d4faSjeremylt     if (!delegate)
468c042f62fSJeremy L Thompson       // LCOV_EXCL_START
469e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
470e15f9bd0SJeremy L Thompson                        "Backend does not support ElemRestrictionCreate");
471c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
4725fe0d4faSjeremylt 
473d1d35e2fSjeremylt     ierr = CeedElemRestrictionCreateStrided(delegate, num_elem, elem_size, num_comp,
474d1d35e2fSjeremylt                                             l_size, strides, rstr);
475d979a051Sjeremylt     CeedChk(ierr);
476e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
4775fe0d4faSjeremylt   }
4785fe0d4faSjeremylt 
4794ce2993fSjeremylt   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
4804ce2993fSjeremylt   (*rstr)->ceed = ceed;
4819560d06aSjeremylt   ierr = CeedReference(ceed); CeedChk(ierr);
482d1d35e2fSjeremylt   (*rstr)->ref_count = 1;
483d1d35e2fSjeremylt   (*rstr)->num_elem = num_elem;
484d1d35e2fSjeremylt   (*rstr)->elem_size = elem_size;
485d1d35e2fSjeremylt   (*rstr)->num_comp = num_comp;
486d1d35e2fSjeremylt   (*rstr)->l_size = l_size;
487d1d35e2fSjeremylt   (*rstr)->num_blk = num_elem;
488d1d35e2fSjeremylt   (*rstr)->blk_size = 1;
4897509a596Sjeremylt   ierr = CeedMalloc(3, &(*rstr)->strides); CeedChk(ierr);
4907509a596Sjeremylt   for (int i=0; i<3; i++)
4917509a596Sjeremylt     (*rstr)->strides[i] = strides[i];
4921dfeef1dSjeremylt   ierr = ceed->ElemRestrictionCreate(CEED_MEM_HOST, CEED_OWN_POINTER, NULL,
4931dfeef1dSjeremylt                                      *rstr);
4944b8bea3bSJed Brown   CeedChk(ierr);
495e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
496d7b241e6Sjeremylt }
497d7b241e6Sjeremylt 
498d7b241e6Sjeremylt /**
499b11c1e72Sjeremylt   @brief Create a blocked CeedElemRestriction, typically only called by backends
500d7b241e6Sjeremylt 
501d7b241e6Sjeremylt   @param ceed         A Ceed object where the CeedElemRestriction will be created.
502d1d35e2fSjeremylt   @param num_elem     Number of elements described in the @a offsets array.
503d1d35e2fSjeremylt   @param elem_size    Size (number of unknowns) per element
504d1d35e2fSjeremylt   @param blk_size     Number of elements in a block
505d1d35e2fSjeremylt   @param num_comp     Number of field components per interpolation node
50695bb1877Svaleriabarra                         (1 for scalar fields)
507d1d35e2fSjeremylt   @param comp_stride  Stride between components for the same L-vector "node".
50895e93d34SJeremy L Thompson                         Data for node i, component j, element k can be found in
50995e93d34SJeremy L Thompson                         the L-vector at index
510d1d35e2fSjeremylt                         offsets[i + k*elem_size] + j*comp_stride.
511d1d35e2fSjeremylt   @param l_size       The size of the L-vector. This vector may be larger than
512d979a051Sjeremylt                         the elements and fields given by this restriction.
513d1d35e2fSjeremylt   @param mem_type     Memory type of the @a offsets array, see CeedMemType
514d1d35e2fSjeremylt   @param copy_mode    Copy mode for the @a offsets array, see CeedCopyMode
515d1d35e2fSjeremylt   @param offsets      Array of shape [@a num_elem, @a elem_size]. Row i holds the
516d979a051Sjeremylt                         ordered list of the offsets (into the input CeedVector)
5178795c945Sjeremylt                         for the unknowns corresponding to element i, where
518d1d35e2fSjeremylt                         0 <= i < @a num_elem. All offsets must be in the range
519d1d35e2fSjeremylt                         [0, @a l_size - 1]. The backend will permute and pad this
5208795c945Sjeremylt                         array to the desired ordering for the blocksize, which is
5218795c945Sjeremylt                         typically given by the backend. The default reordering is
5228795c945Sjeremylt                         to interlace elements.
5234ce2993fSjeremylt   @param rstr         Address of the variable where the newly created
524b11c1e72Sjeremylt                         CeedElemRestriction will be stored
525d7b241e6Sjeremylt 
526b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
527dfdf5a53Sjeremylt 
5287a982d89SJeremy L. Thompson   @ref Backend
529b11c1e72Sjeremylt  **/
530d1d35e2fSjeremylt int CeedElemRestrictionCreateBlocked(Ceed ceed, CeedInt num_elem,
531d1d35e2fSjeremylt                                      CeedInt elem_size,
532d1d35e2fSjeremylt                                      CeedInt blk_size, CeedInt num_comp,
533d1d35e2fSjeremylt                                      CeedInt comp_stride, CeedInt l_size,
534d1d35e2fSjeremylt                                      CeedMemType mem_type, CeedCopyMode copy_mode,
535d979a051Sjeremylt                                      const CeedInt *offsets,
5364ce2993fSjeremylt                                      CeedElemRestriction *rstr) {
537d7b241e6Sjeremylt   int ierr;
538d1d35e2fSjeremylt   CeedInt *blk_offsets;
539d1d35e2fSjeremylt   CeedInt num_blk = (num_elem / blk_size) + !!(num_elem % blk_size);
540d7b241e6Sjeremylt 
5415fe0d4faSjeremylt   if (!ceed->ElemRestrictionCreateBlocked) {
5425fe0d4faSjeremylt     Ceed delegate;
543aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
544aefd8378Sjeremylt     CeedChk(ierr);
5455fe0d4faSjeremylt 
5465fe0d4faSjeremylt     if (!delegate)
547c042f62fSJeremy L Thompson       // LCOV_EXCL_START
548e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support "
5491d102b48SJeremy L Thompson                        "ElemRestrictionCreateBlocked");
550c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
5515fe0d4faSjeremylt 
552d1d35e2fSjeremylt     ierr = CeedElemRestrictionCreateBlocked(delegate, num_elem, elem_size, blk_size,
553d1d35e2fSjeremylt                                             num_comp, comp_stride, l_size, mem_type,
554d1d35e2fSjeremylt                                             copy_mode, offsets, rstr);
555d979a051Sjeremylt     CeedChk(ierr);
556e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
5575fe0d4faSjeremylt   }
558d7b241e6Sjeremylt 
5594ce2993fSjeremylt   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
560d7b241e6Sjeremylt 
561d1d35e2fSjeremylt   ierr = CeedCalloc(num_blk*blk_size*elem_size, &blk_offsets); CeedChk(ierr);
562d1d35e2fSjeremylt   ierr = CeedPermutePadOffsets(offsets, blk_offsets, num_blk, num_elem, blk_size,
563d1d35e2fSjeremylt                                elem_size); CeedChk(ierr);
564d7b241e6Sjeremylt 
5654ce2993fSjeremylt   (*rstr)->ceed = ceed;
5669560d06aSjeremylt   ierr = CeedReference(ceed); CeedChk(ierr);
567d1d35e2fSjeremylt   (*rstr)->ref_count = 1;
568d1d35e2fSjeremylt   (*rstr)->num_elem = num_elem;
569d1d35e2fSjeremylt   (*rstr)->elem_size = elem_size;
570d1d35e2fSjeremylt   (*rstr)->num_comp = num_comp;
571d1d35e2fSjeremylt   (*rstr)->comp_stride = comp_stride;
572d1d35e2fSjeremylt   (*rstr)->l_size = l_size;
573d1d35e2fSjeremylt   (*rstr)->num_blk = num_blk;
574d1d35e2fSjeremylt   (*rstr)->blk_size = blk_size;
575667bc5fcSjeremylt   ierr = ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER,
576d1d35e2fSjeremylt          (const CeedInt *) blk_offsets, *rstr); CeedChk(ierr);
577d1d35e2fSjeremylt   if (copy_mode == CEED_OWN_POINTER) {
578d979a051Sjeremylt     ierr = CeedFree(&offsets); CeedChk(ierr);
5791d102b48SJeremy L Thompson   }
580e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
581d7b241e6Sjeremylt }
582d7b241e6Sjeremylt 
583b11c1e72Sjeremylt /**
5847509a596Sjeremylt   @brief Create a blocked strided CeedElemRestriction
5857509a596Sjeremylt 
5867509a596Sjeremylt   @param ceed       A Ceed object where the CeedElemRestriction will be created
587d1d35e2fSjeremylt   @param num_elem   Number of elements described by the restriction
588d1d35e2fSjeremylt   @param elem_size  Size (number of "nodes") per element
589d1d35e2fSjeremylt   @param blk_size   Number of elements in a block
590d1d35e2fSjeremylt   @param num_comp   Number of field components per interpolation node
5917509a596Sjeremylt                       (1 for scalar fields)
592d1d35e2fSjeremylt   @param l_size     The size of the L-vector. This vector may be larger than
593d979a051Sjeremylt                       the elements and fields given by this restriction.
5947509a596Sjeremylt   @param strides    Array for strides between [nodes, components, elements].
59595e93d34SJeremy L Thompson                       Data for node i, component j, element k can be found in
59695e93d34SJeremy L Thompson                       the L-vector at index
59795e93d34SJeremy L Thompson                       i*strides[0] + j*strides[1] + k*strides[2].
59895e93d34SJeremy L Thompson                       @a CEED_STRIDES_BACKEND may be used with vectors created
59995e93d34SJeremy L Thompson                       by a Ceed backend.
6007509a596Sjeremylt   @param rstr       Address of the variable where the newly created
6017509a596Sjeremylt                       CeedElemRestriction will be stored
6027509a596Sjeremylt 
6037509a596Sjeremylt   @return An error code: 0 - success, otherwise - failure
6047509a596Sjeremylt 
6057a982d89SJeremy L. Thompson   @ref User
6067509a596Sjeremylt **/
607d1d35e2fSjeremylt int CeedElemRestrictionCreateBlockedStrided(Ceed ceed, CeedInt num_elem,
608d1d35e2fSjeremylt     CeedInt elem_size, CeedInt blk_size, CeedInt num_comp, CeedInt l_size,
6098621c6c6SJeremy L Thompson     const CeedInt strides[3], CeedElemRestriction *rstr) {
6107509a596Sjeremylt   int ierr;
611d1d35e2fSjeremylt   CeedInt num_blk = (num_elem / blk_size) + !!(num_elem % blk_size);
6127509a596Sjeremylt 
6137509a596Sjeremylt   if (!ceed->ElemRestrictionCreateBlocked) {
6147509a596Sjeremylt     Ceed delegate;
6157509a596Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
6167509a596Sjeremylt     CeedChk(ierr);
6177509a596Sjeremylt 
6187509a596Sjeremylt     if (!delegate)
6197509a596Sjeremylt       // LCOV_EXCL_START
620e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support "
6217509a596Sjeremylt                        "ElemRestrictionCreateBlocked");
6227509a596Sjeremylt     // LCOV_EXCL_STOP
6237509a596Sjeremylt 
624d1d35e2fSjeremylt     ierr = CeedElemRestrictionCreateBlockedStrided(delegate, num_elem, elem_size,
625d1d35e2fSjeremylt            blk_size, num_comp, l_size, strides, rstr); CeedChk(ierr);
626e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
6277509a596Sjeremylt   }
6287509a596Sjeremylt 
6297509a596Sjeremylt   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
6307509a596Sjeremylt 
6317509a596Sjeremylt   (*rstr)->ceed = ceed;
6329560d06aSjeremylt   ierr = CeedReference(ceed); CeedChk(ierr);
633d1d35e2fSjeremylt   (*rstr)->ref_count = 1;
634d1d35e2fSjeremylt   (*rstr)->num_elem = num_elem;
635d1d35e2fSjeremylt   (*rstr)->elem_size = elem_size;
636d1d35e2fSjeremylt   (*rstr)->num_comp = num_comp;
637d1d35e2fSjeremylt   (*rstr)->l_size = l_size;
638d1d35e2fSjeremylt   (*rstr)->num_blk = num_blk;
639d1d35e2fSjeremylt   (*rstr)->blk_size = blk_size;
6407509a596Sjeremylt   ierr = CeedMalloc(3, &(*rstr)->strides); CeedChk(ierr);
6417509a596Sjeremylt   for (int i=0; i<3; i++)
6427509a596Sjeremylt     (*rstr)->strides[i] = strides[i];
6437509a596Sjeremylt   ierr = ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER,
6447509a596Sjeremylt          NULL, *rstr); CeedChk(ierr);
645e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6467509a596Sjeremylt }
6477509a596Sjeremylt 
6487509a596Sjeremylt /**
6499560d06aSjeremylt   @brief Copy the pointer to a CeedElemRestriction. Both pointers should
6509560d06aSjeremylt            be destroyed with `CeedElemRestrictionDestroy()`;
6519560d06aSjeremylt            Note: If `*rstr_copy` is non-NULL, then it is assumed that
6529560d06aSjeremylt            `*rstr_copy` is a pointer to a CeedElemRestriction. This
6539560d06aSjeremylt            CeedElemRestriction will be destroyed if `*rstr_copy` is the
6549560d06aSjeremylt            only reference to this CeedElemRestriction.
6559560d06aSjeremylt 
6569560d06aSjeremylt   @param rstr            CeedElemRestriction to copy reference to
6579560d06aSjeremylt   @param[out] rstr_copy  Variable to store copied reference
6589560d06aSjeremylt 
6599560d06aSjeremylt   @return An error code: 0 - success, otherwise - failure
6609560d06aSjeremylt 
6619560d06aSjeremylt   @ref User
6629560d06aSjeremylt **/
6639560d06aSjeremylt int CeedElemRestrictionReferenceCopy(CeedElemRestriction rstr,
6649560d06aSjeremylt                                      CeedElemRestriction *rstr_copy) {
6659560d06aSjeremylt   int ierr;
6669560d06aSjeremylt 
6679560d06aSjeremylt   ierr = CeedElemRestrictionReference(rstr); CeedChk(ierr);
6689560d06aSjeremylt   ierr = CeedElemRestrictionDestroy(rstr_copy); CeedChk(ierr);
6699560d06aSjeremylt   *rstr_copy = rstr;
6709560d06aSjeremylt   return CEED_ERROR_SUCCESS;
6719560d06aSjeremylt }
6729560d06aSjeremylt 
6739560d06aSjeremylt /**
674b11c1e72Sjeremylt   @brief Create CeedVectors associated with a CeedElemRestriction
675b11c1e72Sjeremylt 
6764ce2993fSjeremylt   @param rstr   CeedElemRestriction
677d1d35e2fSjeremylt   @param l_vec  The address of the L-vector to be created, or NULL
678d1d35e2fSjeremylt   @param e_vec  The address of the E-vector to be created, or NULL
679b11c1e72Sjeremylt 
680b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
681dfdf5a53Sjeremylt 
6827a982d89SJeremy L. Thompson   @ref User
683b11c1e72Sjeremylt **/
684d1d35e2fSjeremylt int CeedElemRestrictionCreateVector(CeedElemRestriction rstr, CeedVector *l_vec,
685d1d35e2fSjeremylt                                     CeedVector *e_vec) {
686d7b241e6Sjeremylt   int ierr;
687d1d35e2fSjeremylt   CeedInt e_size, l_size;
688d1d35e2fSjeremylt   l_size = rstr->l_size;
689d1d35e2fSjeremylt   e_size = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp;
690d1d35e2fSjeremylt   if (l_vec) {
691d1d35e2fSjeremylt     ierr = CeedVectorCreate(rstr->ceed, l_size, l_vec); CeedChk(ierr);
692d7b241e6Sjeremylt   }
693d1d35e2fSjeremylt   if (e_vec) {
694d1d35e2fSjeremylt     ierr = CeedVectorCreate(rstr->ceed, e_size, e_vec); CeedChk(ierr);
695d7b241e6Sjeremylt   }
696e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
697d7b241e6Sjeremylt }
698d7b241e6Sjeremylt 
699d7b241e6Sjeremylt /**
700d9e1f99aSValeria Barra   @brief Restrict an L-vector to an E-vector or apply its transpose
701d7b241e6Sjeremylt 
7024ce2993fSjeremylt   @param rstr    CeedElemRestriction
703d1d35e2fSjeremylt   @param t_mode  Apply restriction or transpose
704d1d35e2fSjeremylt   @param u       Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE)
705d1d35e2fSjeremylt   @param ru      Output vector (of shape [@a num_elem * @a elem_size] when
706d1d35e2fSjeremylt                    t_mode=@ref CEED_NOTRANSPOSE). Ordering of the e-vector is decided
7077aaeacdcSjeremylt                    by the backend.
7084cc79fe7SJed Brown   @param request Request or @ref CEED_REQUEST_IMMEDIATE
709b11c1e72Sjeremylt 
710b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
711dfdf5a53Sjeremylt 
7127a982d89SJeremy L. Thompson   @ref User
713b11c1e72Sjeremylt **/
714d1d35e2fSjeremylt int CeedElemRestrictionApply(CeedElemRestriction rstr, CeedTransposeMode t_mode,
715a8d32208Sjeremylt                              CeedVector u, CeedVector ru,
716a8d32208Sjeremylt                              CeedRequest *request) {
717d7b241e6Sjeremylt   CeedInt m, n;
718d7b241e6Sjeremylt   int ierr;
719d7b241e6Sjeremylt 
720d1d35e2fSjeremylt   if (t_mode == CEED_NOTRANSPOSE) {
721d1d35e2fSjeremylt     m = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp;
722d1d35e2fSjeremylt     n = rstr->l_size;
723d7b241e6Sjeremylt   } else {
724d1d35e2fSjeremylt     m = rstr->l_size;
725d1d35e2fSjeremylt     n = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp;
726d7b241e6Sjeremylt   }
727d7b241e6Sjeremylt   if (n != u->length)
728c042f62fSJeremy L Thompson     // LCOV_EXCL_START
729e15f9bd0SJeremy L Thompson     return CeedError(rstr->ceed, CEED_ERROR_DIMENSION,
730e15f9bd0SJeremy L Thompson                      "Input vector size %d not compatible with "
7311d102b48SJeremy L Thompson                      "element restriction (%d, %d)", u->length, m, n);
732c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
733a8d32208Sjeremylt   if (m != ru->length)
734c042f62fSJeremy L Thompson     // LCOV_EXCL_START
735e15f9bd0SJeremy L Thompson     return CeedError(rstr->ceed, CEED_ERROR_DIMENSION,
736e15f9bd0SJeremy L Thompson                      "Output vector size %d not compatible with "
737a8d32208Sjeremylt                      "element restriction (%d, %d)", ru->length, m, n);
738c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
739d1d35e2fSjeremylt   ierr = rstr->Apply(rstr, t_mode, u, ru, request); CeedChk(ierr);
740e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
741d7b241e6Sjeremylt }
742d7b241e6Sjeremylt 
743d7b241e6Sjeremylt /**
744d9e1f99aSValeria Barra   @brief Restrict an L-vector to a block of an E-vector or apply its transpose
745be9261b7Sjeremylt 
746be9261b7Sjeremylt   @param rstr    CeedElemRestriction
7471f37b403Sjeremylt   @param block   Block number to restrict to/from, i.e. block=0 will handle
748d1d35e2fSjeremylt                    elements [0 : blk_size] and block=3 will handle elements
749d1d35e2fSjeremylt                    [3*blk_size : 4*blk_size]
750d1d35e2fSjeremylt   @param t_mode  Apply restriction or transpose
751d1d35e2fSjeremylt   @param u       Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE)
752d1d35e2fSjeremylt   @param ru      Output vector (of shape [@a blk_size * @a elem_size] when
753d1d35e2fSjeremylt                    t_mode=@ref CEED_NOTRANSPOSE). Ordering of the e-vector is decided
7547aaeacdcSjeremylt                    by the backend.
7554cc79fe7SJed Brown   @param request Request or @ref CEED_REQUEST_IMMEDIATE
756be9261b7Sjeremylt 
757be9261b7Sjeremylt   @return An error code: 0 - success, otherwise - failure
758be9261b7Sjeremylt 
7597a982d89SJeremy L. Thompson   @ref Backend
760be9261b7Sjeremylt **/
761be9261b7Sjeremylt int CeedElemRestrictionApplyBlock(CeedElemRestriction rstr, CeedInt block,
762d1d35e2fSjeremylt                                   CeedTransposeMode t_mode, CeedVector u,
763a8d32208Sjeremylt                                   CeedVector ru, CeedRequest *request) {
764be9261b7Sjeremylt   CeedInt m, n;
765be9261b7Sjeremylt   int ierr;
766be9261b7Sjeremylt 
767d1d35e2fSjeremylt   if (t_mode == CEED_NOTRANSPOSE) {
768d1d35e2fSjeremylt     m = rstr->blk_size * rstr->elem_size * rstr->num_comp;
769d1d35e2fSjeremylt     n = rstr->l_size;
770be9261b7Sjeremylt   } else {
771d1d35e2fSjeremylt     m = rstr->l_size;
772d1d35e2fSjeremylt     n = rstr->blk_size * rstr->elem_size * rstr->num_comp;
773be9261b7Sjeremylt   }
774be9261b7Sjeremylt   if (n != u->length)
775c042f62fSJeremy L Thompson     // LCOV_EXCL_START
776e15f9bd0SJeremy L Thompson     return CeedError(rstr->ceed, CEED_ERROR_DIMENSION,
777e15f9bd0SJeremy L Thompson                      "Input vector size %d not compatible with "
7781d102b48SJeremy L Thompson                      "element restriction (%d, %d)", u->length, m, n);
779c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
780a8d32208Sjeremylt   if (m != ru->length)
781c042f62fSJeremy L Thompson     // LCOV_EXCL_START
782e15f9bd0SJeremy L Thompson     return CeedError(rstr->ceed, CEED_ERROR_DIMENSION,
783e15f9bd0SJeremy L Thompson                      "Output vector size %d not compatible with "
784a8d32208Sjeremylt                      "element restriction (%d, %d)", ru->length, m, n);
785c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
786d1d35e2fSjeremylt   if (rstr->blk_size*block > rstr->num_elem)
787c042f62fSJeremy L Thompson     // LCOV_EXCL_START
788e15f9bd0SJeremy L Thompson     return CeedError(rstr->ceed, CEED_ERROR_DIMENSION,
789e15f9bd0SJeremy L Thompson                      "Cannot retrieve block %d, element %d > "
790d1d35e2fSjeremylt                      "total elements %d", block, rstr->blk_size*block,
791d1d35e2fSjeremylt                      rstr->num_elem);
792c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
793d1d35e2fSjeremylt   ierr = rstr->ApplyBlock(rstr, block, t_mode, u, ru, request);
794be9261b7Sjeremylt   CeedChk(ierr);
795e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
796be9261b7Sjeremylt }
797be9261b7Sjeremylt 
798be9261b7Sjeremylt /**
799b7c9bbdaSJeremy L Thompson   @brief Get the Ceed associated with a CeedElemRestriction
800b7c9bbdaSJeremy L Thompson 
801b7c9bbdaSJeremy L Thompson   @param rstr       CeedElemRestriction
802b7c9bbdaSJeremy L Thompson   @param[out] ceed  Variable to store Ceed
803b7c9bbdaSJeremy L Thompson 
804b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
805b7c9bbdaSJeremy L Thompson 
806b7c9bbdaSJeremy L Thompson   @ref Advanced
807b7c9bbdaSJeremy L Thompson **/
808b7c9bbdaSJeremy L Thompson int CeedElemRestrictionGetCeed(CeedElemRestriction rstr, Ceed *ceed) {
809b7c9bbdaSJeremy L Thompson   *ceed = rstr->ceed;
810b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
811b7c9bbdaSJeremy L Thompson }
812b7c9bbdaSJeremy L Thompson 
813b7c9bbdaSJeremy L Thompson /**
814d979a051Sjeremylt   @brief Get the L-vector component stride
815a681ae63Sjeremylt 
816a681ae63Sjeremylt   @param rstr              CeedElemRestriction
817d1d35e2fSjeremylt   @param[out] comp_stride  Variable to store component stride
818a681ae63Sjeremylt 
819a681ae63Sjeremylt   @return An error code: 0 - success, otherwise - failure
820a681ae63Sjeremylt 
821b7c9bbdaSJeremy L Thompson   @ref Advanced
822a681ae63Sjeremylt **/
823d979a051Sjeremylt int CeedElemRestrictionGetCompStride(CeedElemRestriction rstr,
824d1d35e2fSjeremylt                                      CeedInt *comp_stride) {
825d1d35e2fSjeremylt   *comp_stride = rstr->comp_stride;
826e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
827a681ae63Sjeremylt }
828a681ae63Sjeremylt 
829a681ae63Sjeremylt /**
830a681ae63Sjeremylt   @brief Get the total number of elements in the range of a CeedElemRestriction
831a681ae63Sjeremylt 
832a681ae63Sjeremylt   @param rstr           CeedElemRestriction
833d1d35e2fSjeremylt   @param[out] num_elem  Variable to store number of elements
834a681ae63Sjeremylt 
835a681ae63Sjeremylt   @return An error code: 0 - success, otherwise - failure
836a681ae63Sjeremylt 
837b7c9bbdaSJeremy L Thompson   @ref Advanced
838a681ae63Sjeremylt **/
839a681ae63Sjeremylt int CeedElemRestrictionGetNumElements(CeedElemRestriction rstr,
840d1d35e2fSjeremylt                                       CeedInt *num_elem) {
841d1d35e2fSjeremylt   *num_elem = rstr->num_elem;
842e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
843a681ae63Sjeremylt }
844a681ae63Sjeremylt 
845a681ae63Sjeremylt /**
846a681ae63Sjeremylt   @brief Get the size of elements in the CeedElemRestriction
847a681ae63Sjeremylt 
848a681ae63Sjeremylt   @param rstr            CeedElemRestriction
849d1d35e2fSjeremylt   @param[out] elem_size  Variable to store size of elements
850a681ae63Sjeremylt 
851a681ae63Sjeremylt   @return An error code: 0 - success, otherwise - failure
852a681ae63Sjeremylt 
853b7c9bbdaSJeremy L Thompson   @ref Advanced
854a681ae63Sjeremylt **/
855a681ae63Sjeremylt int CeedElemRestrictionGetElementSize(CeedElemRestriction rstr,
856d1d35e2fSjeremylt                                       CeedInt *elem_size) {
857d1d35e2fSjeremylt   *elem_size = rstr->elem_size;
858e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
859a681ae63Sjeremylt }
860a681ae63Sjeremylt 
861a681ae63Sjeremylt /**
862d979a051Sjeremylt   @brief Get the size of the l-vector for a CeedElemRestriction
863a681ae63Sjeremylt 
864a681ae63Sjeremylt   @param rstr         CeedElemRestriction
865d1d35e2fSjeremylt   @param[out] l_size  Variable to store number of nodes
866a681ae63Sjeremylt 
867a681ae63Sjeremylt   @return An error code: 0 - success, otherwise - failure
868a681ae63Sjeremylt 
869b7c9bbdaSJeremy L Thompson   @ref Advanced
870a681ae63Sjeremylt **/
871d979a051Sjeremylt int CeedElemRestrictionGetLVectorSize(CeedElemRestriction rstr,
872d1d35e2fSjeremylt                                       CeedInt *l_size) {
873d1d35e2fSjeremylt   *l_size = rstr->l_size;
874e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
875a681ae63Sjeremylt }
876a681ae63Sjeremylt 
877a681ae63Sjeremylt /**
878a681ae63Sjeremylt   @brief Get the number of components in the elements of a
879a681ae63Sjeremylt          CeedElemRestriction
880a681ae63Sjeremylt 
881a681ae63Sjeremylt   @param rstr           CeedElemRestriction
882d1d35e2fSjeremylt   @param[out] num_comp  Variable to store number of components
883a681ae63Sjeremylt 
884a681ae63Sjeremylt   @return An error code: 0 - success, otherwise - failure
885a681ae63Sjeremylt 
886b7c9bbdaSJeremy L Thompson   @ref Advanced
887a681ae63Sjeremylt **/
888a681ae63Sjeremylt int CeedElemRestrictionGetNumComponents(CeedElemRestriction rstr,
889d1d35e2fSjeremylt                                         CeedInt *num_comp) {
890d1d35e2fSjeremylt   *num_comp = rstr->num_comp;
891e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
892a681ae63Sjeremylt }
893a681ae63Sjeremylt 
894a681ae63Sjeremylt /**
895a681ae63Sjeremylt   @brief Get the number of blocks in a CeedElemRestriction
896a681ae63Sjeremylt 
897a681ae63Sjeremylt   @param rstr            CeedElemRestriction
898d1d35e2fSjeremylt   @param[out] num_block  Variable to store number of blocks
899a681ae63Sjeremylt 
900a681ae63Sjeremylt   @return An error code: 0 - success, otherwise - failure
901a681ae63Sjeremylt 
902b7c9bbdaSJeremy L Thompson   @ref Advanced
903a681ae63Sjeremylt **/
904a681ae63Sjeremylt int CeedElemRestrictionGetNumBlocks(CeedElemRestriction rstr,
905d1d35e2fSjeremylt                                     CeedInt *num_block) {
906d1d35e2fSjeremylt   *num_block = rstr->num_blk;
907e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
908a681ae63Sjeremylt }
909a681ae63Sjeremylt 
910a681ae63Sjeremylt /**
911a681ae63Sjeremylt   @brief Get the size of blocks in the CeedElemRestriction
912a681ae63Sjeremylt 
913a681ae63Sjeremylt   @param rstr           CeedElemRestriction
914d1d35e2fSjeremylt   @param[out] blk_size  Variable to store size of blocks
915a681ae63Sjeremylt 
916a681ae63Sjeremylt   @return An error code: 0 - success, otherwise - failure
917a681ae63Sjeremylt 
918b7c9bbdaSJeremy L Thompson   @ref Advanced
919a681ae63Sjeremylt **/
920a681ae63Sjeremylt int CeedElemRestrictionGetBlockSize(CeedElemRestriction rstr,
921d1d35e2fSjeremylt                                     CeedInt *blk_size) {
922d1d35e2fSjeremylt   *blk_size = rstr->blk_size;
923e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
924a681ae63Sjeremylt }
925a681ae63Sjeremylt 
926a681ae63Sjeremylt /**
927d9e1f99aSValeria Barra   @brief Get the multiplicity of nodes in a CeedElemRestriction
9281469ee4dSjeremylt 
9291469ee4dSjeremylt   @param rstr       CeedElemRestriction
930d1d35e2fSjeremylt   @param[out] mult  Vector to store multiplicity (of size l_size)
9311469ee4dSjeremylt 
9321469ee4dSjeremylt   @return An error code: 0 - success, otherwise - failure
9331469ee4dSjeremylt 
9347a982d89SJeremy L. Thompson   @ref User
9351469ee4dSjeremylt **/
9361469ee4dSjeremylt int CeedElemRestrictionGetMultiplicity(CeedElemRestriction rstr,
9371469ee4dSjeremylt                                        CeedVector mult) {
9381469ee4dSjeremylt   int ierr;
939d1d35e2fSjeremylt   CeedVector e_vec;
9401469ee4dSjeremylt 
94125509ebbSRezgar Shakeri   // Create e_vec to hold intermediate computation in E^T (E 1)
942d1d35e2fSjeremylt   ierr = CeedElemRestrictionCreateVector(rstr, NULL, &e_vec); CeedChk(ierr);
9431469ee4dSjeremylt 
94425509ebbSRezgar Shakeri   // Compute e_vec = E * 1
94525509ebbSRezgar Shakeri   ierr = CeedVectorSetValue(mult, 1.0); CeedChk(ierr);
94625509ebbSRezgar Shakeri   ierr = CeedElemRestrictionApply(rstr, CEED_NOTRANSPOSE, mult, e_vec,
94725509ebbSRezgar Shakeri                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
94825509ebbSRezgar Shakeri   // Compute multiplicity, mult = E^T * e_vec = E^T (E 1)
94925509ebbSRezgar Shakeri   ierr = CeedVectorSetValue(mult, 0.0); CeedChk(ierr);
950d1d35e2fSjeremylt   ierr = CeedElemRestrictionApply(rstr, CEED_TRANSPOSE, e_vec, mult,
951efc78312Sjeremylt                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
9521469ee4dSjeremylt   // Cleanup
953d1d35e2fSjeremylt   ierr = CeedVectorDestroy(&e_vec); CeedChk(ierr);
954e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
9551469ee4dSjeremylt }
9561469ee4dSjeremylt 
9571469ee4dSjeremylt /**
958f02ca4a2SJed Brown   @brief View a CeedElemRestriction
959f02ca4a2SJed Brown 
960f02ca4a2SJed Brown   @param[in] rstr    CeedElemRestriction to view
961f02ca4a2SJed Brown   @param[in] stream  Stream to write; typically stdout/stderr or a file
962f02ca4a2SJed Brown 
963f02ca4a2SJed Brown   @return Error code: 0 - success, otherwise - failure
964f02ca4a2SJed Brown 
9657a982d89SJeremy L. Thompson   @ref User
966f02ca4a2SJed Brown **/
967f02ca4a2SJed Brown int CeedElemRestrictionView(CeedElemRestriction rstr, FILE *stream) {
9687509a596Sjeremylt   char stridesstr[500];
9697509a596Sjeremylt   if (rstr->strides)
9707509a596Sjeremylt     sprintf(stridesstr, "[%d, %d, %d]", rstr->strides[0], rstr->strides[1],
9717509a596Sjeremylt             rstr->strides[2]);
972d979a051Sjeremylt   else
973d1d35e2fSjeremylt     sprintf(stridesstr, "%d", rstr->comp_stride);
9747509a596Sjeremylt 
9750036de2cSjeremylt   fprintf(stream, "%sCeedElemRestriction from (%d, %d) to %d elements with %d "
976d1d35e2fSjeremylt           "nodes each and %s %s\n", rstr->blk_size > 1 ? "Blocked " : "",
977d1d35e2fSjeremylt           rstr->l_size, rstr->num_comp, rstr->num_elem, rstr->elem_size,
978d979a051Sjeremylt           rstr->strides ? "strides" : "component stride", stridesstr);
979e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
980f02ca4a2SJed Brown }
981f02ca4a2SJed Brown 
982f02ca4a2SJed Brown /**
983b11c1e72Sjeremylt   @brief Destroy a CeedElemRestriction
984b11c1e72Sjeremylt 
9854ce2993fSjeremylt   @param rstr  CeedElemRestriction to destroy
986b11c1e72Sjeremylt 
987b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
988dfdf5a53Sjeremylt 
9897a982d89SJeremy L. Thompson   @ref User
990b11c1e72Sjeremylt **/
9914ce2993fSjeremylt int CeedElemRestrictionDestroy(CeedElemRestriction *rstr) {
992d7b241e6Sjeremylt   int ierr;
993d7b241e6Sjeremylt 
994d1d35e2fSjeremylt   if (!*rstr || --(*rstr)->ref_count > 0) return CEED_ERROR_SUCCESS;
995d1d35e2fSjeremylt   if ((*rstr)->num_readers)
9968229195eSjeremylt     // LCOV_EXCL_START
997e15f9bd0SJeremy L Thompson     return CeedError((*rstr)->ceed, CEED_ERROR_ACCESS,
998e15f9bd0SJeremy L Thompson                      "Cannot destroy CeedElemRestriction, "
999430758c8SJeremy L Thompson                      "a process has read access to the offset data");
10008229195eSjeremylt   // LCOV_EXCL_STOP
10014ce2993fSjeremylt   if ((*rstr)->Destroy) {
10024ce2993fSjeremylt     ierr = (*rstr)->Destroy(*rstr); CeedChk(ierr);
1003d7b241e6Sjeremylt   }
10047509a596Sjeremylt   ierr = CeedFree(&(*rstr)->strides); CeedChk(ierr);
10054ce2993fSjeremylt   ierr = CeedDestroy(&(*rstr)->ceed); CeedChk(ierr);
10064ce2993fSjeremylt   ierr = CeedFree(rstr); CeedChk(ierr);
1007e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1008d7b241e6Sjeremylt }
1009d7b241e6Sjeremylt 
1010d7b241e6Sjeremylt /// @}
1011