xref: /libCEED/interface/ceed-elemrestriction.c (revision 5c7e0f51a31e0024d50a04e94a1dc775c96aef1e)
13d8e8822SJeremy L Thompson // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors.
23d8e8822SJeremy L Thompson // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
3d7b241e6Sjeremylt //
43d8e8822SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause
5d7b241e6Sjeremylt //
63d8e8822SJeremy L Thompson // This file is part of CEED:  http://github.com/ceed
7d7b241e6Sjeremylt 
83d576824SJeremy L Thompson #include <ceed-impl.h>
949aac155SJeremy L Thompson #include <ceed.h>
102b730f8bSJeremy L Thompson #include <ceed/backend.h>
113d576824SJeremy L Thompson #include <stdbool.h>
123d576824SJeremy L Thompson #include <stdio.h>
13c17ec2beSJeremy L Thompson #include <string.h>
14d7b241e6Sjeremylt 
157a982d89SJeremy L. Thompson /// @file
167a982d89SJeremy L. Thompson /// Implementation of CeedElemRestriction interfaces
177a982d89SJeremy L. Thompson 
187a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
197a982d89SJeremy L. Thompson /// CeedElemRestriction Library Internal Functions
207a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
217a982d89SJeremy L. Thompson /// @addtogroup CeedElemRestrictionDeveloper
227a982d89SJeremy L. Thompson /// @{
237a982d89SJeremy L. Thompson 
247a982d89SJeremy L. Thompson /**
25ca94c3ddSJeremy L Thompson   @brief Permute and pad offsets for a blocked `CeedElemRestriction`
267a982d89SJeremy L. Thompson 
27ca94c3ddSJeremy L Thompson   @param[in]  offsets       Array of shape `[num_elem, elem_size]`
28ca94c3ddSJeremy L Thompson   @param[out] block_offsets Array of permuted and padded array values of shape `[num_block, elem_size, block_size]`
29e7f679fcSJeremy L Thompson   @param[in]  num_block     Number of blocks
30ea61e9acSJeremy L Thompson   @param[in]  num_elem      Number of elements
31e7f679fcSJeremy L Thompson   @param[in]  block_size    Number of elements in a block
32ea61e9acSJeremy L Thompson   @param[in]  elem_size     Size of each element
337a982d89SJeremy L. Thompson 
347a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
357a982d89SJeremy L. Thompson 
367a982d89SJeremy L. Thompson   @ref Utility
377a982d89SJeremy L. Thompson **/
38e7f679fcSJeremy L Thompson int CeedPermutePadOffsets(const CeedInt *offsets, CeedInt *block_offsets, CeedInt num_block, CeedInt num_elem, CeedInt block_size,
39e7f679fcSJeremy L Thompson                           CeedInt elem_size) {
40e7f679fcSJeremy L Thompson   for (CeedInt e = 0; e < num_block * block_size; e += block_size) {
41e7f679fcSJeremy L Thompson     for (CeedInt j = 0; j < block_size; j++) {
422b730f8bSJeremy L Thompson       for (CeedInt k = 0; k < elem_size; k++) {
43e7f679fcSJeremy L Thompson         block_offsets[e * elem_size + k * block_size + j] = offsets[CeedIntMin(e + j, num_elem - 1) * elem_size + k];
442b730f8bSJeremy L Thompson       }
452b730f8bSJeremy L Thompson     }
462b730f8bSJeremy L Thompson   }
47e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
487a982d89SJeremy L. Thompson }
497a982d89SJeremy L. Thompson 
5077d1c127SSebastian Grimberg /**
51ca94c3ddSJeremy L Thompson   @brief Permute and pad orientations for a blocked `CeedElemRestriction`
5277d1c127SSebastian Grimberg 
53ca94c3ddSJeremy L Thompson   @param[in]  orients       Array of shape `[num_elem, elem_size]`
54ca94c3ddSJeremy L Thompson   @param[out] block_orients Array of permuted and padded array values of shape `[num_block, elem_size, block_size]`
55e7f679fcSJeremy L Thompson   @param[in]  num_block     Number of blocks
5677d1c127SSebastian Grimberg   @param[in]  num_elem      Number of elements
57e7f679fcSJeremy L Thompson   @param[in]  block_size    Number of elements in a block
5877d1c127SSebastian Grimberg   @param[in]  elem_size     Size of each element
5977d1c127SSebastian Grimberg 
6077d1c127SSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
6177d1c127SSebastian Grimberg 
6277d1c127SSebastian Grimberg   @ref Utility
6377d1c127SSebastian Grimberg **/
64e7f679fcSJeremy L Thompson int CeedPermutePadOrients(const bool *orients, bool *block_orients, CeedInt num_block, CeedInt num_elem, CeedInt block_size, CeedInt elem_size) {
65e7f679fcSJeremy L Thompson   for (CeedInt e = 0; e < num_block * block_size; e += block_size) {
66e7f679fcSJeremy L Thompson     for (CeedInt j = 0; j < block_size; j++) {
6777d1c127SSebastian Grimberg       for (CeedInt k = 0; k < elem_size; k++) {
68e7f679fcSJeremy L Thompson         block_orients[e * elem_size + k * block_size + j] = orients[CeedIntMin(e + j, num_elem - 1) * elem_size + k];
6977d1c127SSebastian Grimberg       }
7077d1c127SSebastian Grimberg     }
7177d1c127SSebastian Grimberg   }
7277d1c127SSebastian Grimberg   return CEED_ERROR_SUCCESS;
7377d1c127SSebastian Grimberg }
7477d1c127SSebastian Grimberg 
750c73c039SSebastian Grimberg /**
76ca94c3ddSJeremy L Thompson   @brief Permute and pad curl-conforming orientations for a blocked `CeedElemRestriction`
770c73c039SSebastian Grimberg 
78*5c7e0f51SSebastian Grimberg   @param[in]  curl_orients       Array of shape `[num_elem, elem_size]`
79ca94c3ddSJeremy L Thompson   @param[out] block_curl_orients Array of permuted and padded array values of shape `[num_block, elem_size, block_size]`
80e7f679fcSJeremy L Thompson   @param[in]  num_block          Number of blocks
810c73c039SSebastian Grimberg   @param[in]  num_elem           Number of elements
82e7f679fcSJeremy L Thompson   @param[in]  block_size         Number of elements in a block
830c73c039SSebastian Grimberg   @param[in]  elem_size          Size of each element
840c73c039SSebastian Grimberg 
850c73c039SSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
860c73c039SSebastian Grimberg 
870c73c039SSebastian Grimberg   @ref Utility
880c73c039SSebastian Grimberg **/
89e7f679fcSJeremy L Thompson int CeedPermutePadCurlOrients(const CeedInt8 *curl_orients, CeedInt8 *block_curl_orients, CeedInt num_block, CeedInt num_elem, CeedInt block_size,
900c73c039SSebastian Grimberg                               CeedInt elem_size) {
91e7f679fcSJeremy L Thompson   for (CeedInt e = 0; e < num_block * block_size; e += block_size) {
92e7f679fcSJeremy L Thompson     for (CeedInt j = 0; j < block_size; j++) {
930c73c039SSebastian Grimberg       for (CeedInt k = 0; k < elem_size; k++) {
94e7f679fcSJeremy L Thompson         block_curl_orients[e * elem_size + k * block_size + j] = curl_orients[CeedIntMin(e + j, num_elem - 1) * elem_size + k];
950c73c039SSebastian Grimberg       }
960c73c039SSebastian Grimberg     }
970c73c039SSebastian Grimberg   }
980c73c039SSebastian Grimberg   return CEED_ERROR_SUCCESS;
990c73c039SSebastian Grimberg }
1000c73c039SSebastian Grimberg 
1017a982d89SJeremy L. Thompson /// @}
1027a982d89SJeremy L. Thompson 
1037a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
1047a982d89SJeremy L. Thompson /// CeedElemRestriction Backend API
1057a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
1067a982d89SJeremy L. Thompson /// @addtogroup CeedElemRestrictionBackend
1077a982d89SJeremy L. Thompson /// @{
1087a982d89SJeremy L. Thompson 
1097a982d89SJeremy L. Thompson /**
110ca94c3ddSJeremy L Thompson   @brief Get the type of a `CeedElemRestriction`
111a681ae63Sjeremylt 
112ca94c3ddSJeremy L Thompson   @param[in]  rstr      `CeedElemRestriction`
113fcbe8c06SSebastian Grimberg   @param[out] rstr_type Variable to store restriction type
114fcbe8c06SSebastian Grimberg 
115fcbe8c06SSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
116fcbe8c06SSebastian Grimberg 
117fcbe8c06SSebastian Grimberg   @ref Backend
118fcbe8c06SSebastian Grimberg **/
119fcbe8c06SSebastian Grimberg int CeedElemRestrictionGetType(CeedElemRestriction rstr, CeedRestrictionType *rstr_type) {
120fcbe8c06SSebastian Grimberg   *rstr_type = rstr->rstr_type;
121fcbe8c06SSebastian Grimberg   return CEED_ERROR_SUCCESS;
122fcbe8c06SSebastian Grimberg }
123fcbe8c06SSebastian Grimberg 
124fcbe8c06SSebastian Grimberg /**
125ca94c3ddSJeremy L Thompson   @brief Get the strided status of a `CeedElemRestriction`
126fcbe8c06SSebastian Grimberg 
127ca94c3ddSJeremy L Thompson   @param[in]  rstr       `CeedElemRestriction`
128ca94c3ddSJeremy L Thompson   @param[out] is_strided Variable to store strided status
129ca94c3ddSJeremy L Thompson 
130ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
131ca94c3ddSJeremy L Thompson 
132ca94c3ddSJeremy L Thompson   @ref Backend
133fcbe8c06SSebastian Grimberg **/
134fcbe8c06SSebastian Grimberg int CeedElemRestrictionIsStrided(CeedElemRestriction rstr, bool *is_strided) {
135fcbe8c06SSebastian Grimberg   *is_strided = (rstr->rstr_type == CEED_RESTRICTION_STRIDED);
136fcbe8c06SSebastian Grimberg   return CEED_ERROR_SUCCESS;
137fcbe8c06SSebastian Grimberg }
138fcbe8c06SSebastian Grimberg 
139fcbe8c06SSebastian Grimberg /**
140ca94c3ddSJeremy L Thompson   @brief Get the points status of a `CeedElemRestriction`
1413ac8f562SJeremy L Thompson 
142ca94c3ddSJeremy L Thompson   @param[in]  rstr      `CeedElemRestriction`
143ca94c3ddSJeremy L Thompson   @param[out] is_points Variable to store points status
144ca94c3ddSJeremy L Thompson 
145ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
146ca94c3ddSJeremy L Thompson 
147ca94c3ddSJeremy L Thompson   @ref Backend
1483ac8f562SJeremy L Thompson **/
1493ac8f562SJeremy L Thompson int CeedElemRestrictionIsPoints(CeedElemRestriction rstr, bool *is_points) {
1503ac8f562SJeremy L Thompson   *is_points = (rstr->rstr_type == CEED_RESTRICTION_POINTS);
1513ac8f562SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1523ac8f562SJeremy L Thompson }
1533ac8f562SJeremy L Thompson 
1543ac8f562SJeremy L Thompson /**
155ca94c3ddSJeremy L Thompson   @brief Check if two `CeedElemRestriction` created with @ref CeedElemRestrictionCreateAtPoints() and use the same points per element
15648acf710SJeremy L Thompson 
157ca94c3ddSJeremy L Thompson   @param[in]  rstr_a         First `CeedElemRestriction`
158ca94c3ddSJeremy L Thompson   @param[in]  rstr_b         Second `CeedElemRestriction`
15948acf710SJeremy L Thompson   @param[out] are_compatible Variable to store compatibility status
160ca94c3ddSJeremy L Thompson 
161ca94c3ddSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
162ca94c3ddSJeremy L Thompson 
163ca94c3ddSJeremy L Thompson   @ref Backend
16448acf710SJeremy L Thompson **/
16548acf710SJeremy L Thompson int CeedElemRestrictionAtPointsAreCompatible(CeedElemRestriction rstr_a, CeedElemRestriction rstr_b, bool *are_compatible) {
16648acf710SJeremy L Thompson   CeedInt num_elem_a, num_elem_b, num_points_a, num_points_b;
16748acf710SJeremy L Thompson 
16848acf710SJeremy L Thompson   // Cannot compare non-points restrictions
169ca94c3ddSJeremy L Thompson   CeedCheck(rstr_a->rstr_type == CEED_RESTRICTION_POINTS, rstr_a->ceed, CEED_ERROR_UNSUPPORTED, "First CeedElemRestriction must be AtPoints");
170ca94c3ddSJeremy L Thompson   CeedCheck(rstr_b->rstr_type == CEED_RESTRICTION_POINTS, rstr_b->ceed, CEED_ERROR_UNSUPPORTED, "Second CeedElemRestriction must be AtPoints");
17148acf710SJeremy L Thompson 
17248acf710SJeremy L Thompson   CeedCall(CeedElemRestrictionGetNumElements(rstr_a, &num_elem_a));
17348acf710SJeremy L Thompson   CeedCall(CeedElemRestrictionGetNumElements(rstr_b, &num_elem_b));
17448acf710SJeremy L Thompson   CeedCall(CeedElemRestrictionGetNumPoints(rstr_a, &num_points_a));
17548acf710SJeremy L Thompson   CeedCall(CeedElemRestrictionGetNumPoints(rstr_b, &num_points_b));
17648acf710SJeremy L Thompson 
17748acf710SJeremy L Thompson   // Check size and contents of offsets arrays
17848acf710SJeremy L Thompson   *are_compatible = true;
17948acf710SJeremy L Thompson   if (num_elem_a != num_elem_b) *are_compatible = false;
18048acf710SJeremy L Thompson   if (num_points_a != num_points_b) *are_compatible = false;
18148acf710SJeremy L Thompson   if (*are_compatible) {
18248acf710SJeremy L Thompson     const CeedInt *offsets_a, *offsets_b;
18348acf710SJeremy L Thompson 
18448acf710SJeremy L Thompson     CeedCall(CeedElemRestrictionGetOffsets(rstr_a, CEED_MEM_HOST, &offsets_a));
18548acf710SJeremy L Thompson     CeedCall(CeedElemRestrictionGetOffsets(rstr_b, CEED_MEM_HOST, &offsets_b));
18648acf710SJeremy L Thompson     for (CeedInt i = 0; i < num_elem_a + 1 + num_points_a; i++) *are_compatible &= offsets_a[i] == offsets_b[i];
18748acf710SJeremy L Thompson     CeedCall(CeedElemRestrictionRestoreOffsets(rstr_a, &offsets_a));
18848acf710SJeremy L Thompson     CeedCall(CeedElemRestrictionRestoreOffsets(rstr_b, &offsets_b));
18948acf710SJeremy L Thompson   }
19048acf710SJeremy L Thompson   return CEED_ERROR_SUCCESS;
19148acf710SJeremy L Thompson }
19248acf710SJeremy L Thompson 
19348acf710SJeremy L Thompson /**
194ca94c3ddSJeremy L Thompson   @brief Get the strides of a strided `CeedElemRestriction`
1957a982d89SJeremy L. Thompson 
196ca94c3ddSJeremy L Thompson   @param[in]  rstr    `CeedElemRestriction`
197a681ae63Sjeremylt   @param[out] strides Variable to store strides array
1987a982d89SJeremy L. Thompson 
1997a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
2007a982d89SJeremy L. Thompson 
2017a982d89SJeremy L. Thompson   @ref Backend
2027a982d89SJeremy L. Thompson **/
2032b730f8bSJeremy L Thompson int CeedElemRestrictionGetStrides(CeedElemRestriction rstr, CeedInt (*strides)[3]) {
204ca94c3ddSJeremy L Thompson   CeedCheck(rstr->strides, rstr->ceed, CEED_ERROR_MINOR, "CeedElemRestriction has no stride data");
2052b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < 3; i++) (*strides)[i] = rstr->strides[i];
206e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2077a982d89SJeremy L. Thompson }
2087a982d89SJeremy L. Thompson 
2097a982d89SJeremy L. Thompson /**
210ca94c3ddSJeremy L Thompson   @brief Get the backend stride status of a `CeedElemRestriction`
21177d1c127SSebastian Grimberg 
212ca94c3ddSJeremy L Thompson   @param[in]  rstr                 `CeedElemRestriction`
21377d1c127SSebastian Grimberg   @param[out] has_backend_strides  Variable to store stride status
21477d1c127SSebastian Grimberg 
21577d1c127SSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
21677d1c127SSebastian Grimberg 
21777d1c127SSebastian Grimberg   @ref Backend
21877d1c127SSebastian Grimberg **/
21977d1c127SSebastian Grimberg int CeedElemRestrictionHasBackendStrides(CeedElemRestriction rstr, bool *has_backend_strides) {
220ca94c3ddSJeremy L Thompson   CeedCheck(rstr->strides, rstr->ceed, CEED_ERROR_MINOR, "CeedElemRestriction has no stride data");
22177d1c127SSebastian Grimberg   *has_backend_strides = ((rstr->strides[0] == CEED_STRIDES_BACKEND[0]) && (rstr->strides[1] == CEED_STRIDES_BACKEND[1]) &&
22277d1c127SSebastian Grimberg                           (rstr->strides[2] == CEED_STRIDES_BACKEND[2]));
22377d1c127SSebastian Grimberg   return CEED_ERROR_SUCCESS;
22477d1c127SSebastian Grimberg }
22577d1c127SSebastian Grimberg 
22677d1c127SSebastian Grimberg /**
227ca94c3ddSJeremy L Thompson   @brief Get read-only access to a `CeedElemRestriction` offsets array by @ref CeedMemType
228bd33150aSjeremylt 
229ca94c3ddSJeremy L Thompson   @param[in]  rstr     `CeedElemRestriction` to retrieve offsets
230fcbe8c06SSebastian Grimberg   @param[in]  mem_type Memory type on which to access the array.
231fcbe8c06SSebastian Grimberg                          If the backend uses a different memory type, this will perform a copy (possibly cached).
232ca94c3ddSJeremy L Thompson   @param[out] offsets  Array on memory type `mem_type`
233bd33150aSjeremylt 
234bd33150aSjeremylt   @return An error code: 0 - success, otherwise - failure
235bd33150aSjeremylt 
236bd33150aSjeremylt   @ref User
237bd33150aSjeremylt **/
2382b730f8bSJeremy L Thompson int CeedElemRestrictionGetOffsets(CeedElemRestriction rstr, CeedMemType mem_type, const CeedInt **offsets) {
2397c1dbaffSSebastian Grimberg   if (rstr->rstr_base) {
2407c1dbaffSSebastian Grimberg     CeedCall(CeedElemRestrictionGetOffsets(rstr->rstr_base, mem_type, offsets));
241c17ec2beSJeremy L Thompson   } else {
242ca94c3ddSJeremy L Thompson     CeedCheck(rstr->GetOffsets, rstr->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support CeedElemRestrictionGetOffsets");
2432b730f8bSJeremy L Thompson     CeedCall(rstr->GetOffsets(rstr, mem_type, offsets));
244d1d35e2fSjeremylt     rstr->num_readers++;
245c17ec2beSJeremy L Thompson   }
246e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
247430758c8SJeremy L Thompson }
248430758c8SJeremy L Thompson 
249430758c8SJeremy L Thompson /**
250ca94c3ddSJeremy L Thompson   @brief Restore an offsets array obtained using @ref CeedElemRestrictionGetOffsets()
251430758c8SJeremy L Thompson 
252ca94c3ddSJeremy L Thompson   @param[in] rstr    `CeedElemRestriction` to restore
253ea61e9acSJeremy L Thompson   @param[in] offsets Array of offset data
254430758c8SJeremy L Thompson 
255430758c8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
256430758c8SJeremy L Thompson 
257430758c8SJeremy L Thompson   @ref User
258430758c8SJeremy L Thompson **/
2592b730f8bSJeremy L Thompson int CeedElemRestrictionRestoreOffsets(CeedElemRestriction rstr, const CeedInt **offsets) {
2607c1dbaffSSebastian Grimberg   if (rstr->rstr_base) {
2617c1dbaffSSebastian Grimberg     CeedCall(CeedElemRestrictionRestoreOffsets(rstr->rstr_base, offsets));
262c17ec2beSJeremy L Thompson   } else {
263430758c8SJeremy L Thompson     *offsets = NULL;
264d1d35e2fSjeremylt     rstr->num_readers--;
265c17ec2beSJeremy L Thompson   }
266e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
267bd33150aSjeremylt }
268bd33150aSjeremylt 
269bd33150aSjeremylt /**
270ca94c3ddSJeremy L Thompson   @brief Get read-only access to a `CeedElemRestriction` orientations array by @ref CeedMemType
2713ac43b2cSJeremy L Thompson 
272ca94c3ddSJeremy L Thompson   @param[in]  rstr     `CeedElemRestriction` to retrieve orientations
273fcbe8c06SSebastian Grimberg   @param[in]  mem_type Memory type on which to access the array.
274fcbe8c06SSebastian Grimberg                          If the backend uses a different memory type, this will perform a copy (possibly cached).
275ca94c3ddSJeremy L Thompson   @param[out] orients  Array on memory type `mem_type`
2763ac43b2cSJeremy L Thompson 
2773ac43b2cSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
2783ac43b2cSJeremy L Thompson 
27977d1c127SSebastian Grimberg   @ref User
2803ac43b2cSJeremy L Thompson **/
28177d1c127SSebastian Grimberg int CeedElemRestrictionGetOrientations(CeedElemRestriction rstr, CeedMemType mem_type, const bool **orients) {
282ca94c3ddSJeremy L Thompson   CeedCheck(rstr->GetOrientations, rstr->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support CeedElemRestrictionGetOrientations");
28377d1c127SSebastian Grimberg   CeedCall(rstr->GetOrientations(rstr, mem_type, orients));
28477d1c127SSebastian Grimberg   rstr->num_readers++;
285e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2863ac43b2cSJeremy L Thompson }
2873ac43b2cSJeremy L Thompson 
2883ac43b2cSJeremy L Thompson /**
289ca94c3ddSJeremy L Thompson   @brief Restore an orientations array obtained using @ref CeedElemRestrictionGetOrientations()
290b435c5a6Srezgarshakeri 
291ca94c3ddSJeremy L Thompson   @param[in] rstr    `CeedElemRestriction` to restore
29277d1c127SSebastian Grimberg   @param[in] orients Array of orientation data
293b435c5a6Srezgarshakeri 
294b435c5a6Srezgarshakeri   @return An error code: 0 - success, otherwise - failure
295b435c5a6Srezgarshakeri 
29677d1c127SSebastian Grimberg   @ref User
297b435c5a6Srezgarshakeri **/
29877d1c127SSebastian Grimberg int CeedElemRestrictionRestoreOrientations(CeedElemRestriction rstr, const bool **orients) {
29977d1c127SSebastian Grimberg   *orients = NULL;
30077d1c127SSebastian Grimberg   rstr->num_readers--;
301b435c5a6Srezgarshakeri   return CEED_ERROR_SUCCESS;
302b435c5a6Srezgarshakeri }
303b435c5a6Srezgarshakeri 
304b435c5a6Srezgarshakeri /**
305ca94c3ddSJeremy L Thompson   @brief Get read-only access to a `CeedElemRestriction` curl-conforming orientations array by @ref CeedMemType
3067a982d89SJeremy L. Thompson 
307ca94c3ddSJeremy L Thompson   @param[in]  rstr         `CeedElemRestriction` to retrieve curl-conforming orientations
308fcbe8c06SSebastian Grimberg   @param[in]  mem_type     Memory type on which to access the array.
309fcbe8c06SSebastian Grimberg                              If the backend uses a different memory type, this will perform a copy (possibly cached).
310ca94c3ddSJeremy L Thompson   @param[out] curl_orients Array on memory type `mem_type`
3117a982d89SJeremy L. Thompson 
3127a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3137a982d89SJeremy L. Thompson 
31477d1c127SSebastian Grimberg   @ref User
3157a982d89SJeremy L. Thompson **/
3160c73c039SSebastian Grimberg int CeedElemRestrictionGetCurlOrientations(CeedElemRestriction rstr, CeedMemType mem_type, const CeedInt8 **curl_orients) {
317ca94c3ddSJeremy L Thompson   CeedCheck(rstr->GetCurlOrientations, rstr->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support CeedElemRestrictionGetCurlOrientations");
31877d1c127SSebastian Grimberg   CeedCall(rstr->GetCurlOrientations(rstr, mem_type, curl_orients));
31977d1c127SSebastian Grimberg   rstr->num_readers++;
32077d1c127SSebastian Grimberg   return CEED_ERROR_SUCCESS;
32177d1c127SSebastian Grimberg }
32277d1c127SSebastian Grimberg 
32377d1c127SSebastian Grimberg /**
324ca94c3ddSJeremy L Thompson   @brief Restore an orientations array obtained using @ref CeedElemRestrictionGetCurlOrientations()
32577d1c127SSebastian Grimberg 
326ca94c3ddSJeremy L Thompson   @param[in] rstr         `CeedElemRestriction` to restore
32777d1c127SSebastian Grimberg   @param[in] curl_orients Array of orientation data
32877d1c127SSebastian Grimberg 
32977d1c127SSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
33077d1c127SSebastian Grimberg 
33177d1c127SSebastian Grimberg   @ref User
33277d1c127SSebastian Grimberg **/
3330c73c039SSebastian Grimberg int CeedElemRestrictionRestoreCurlOrientations(CeedElemRestriction rstr, const CeedInt8 **curl_orients) {
33477d1c127SSebastian Grimberg   *curl_orients = NULL;
33577d1c127SSebastian Grimberg   rstr->num_readers--;
336e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3377a982d89SJeremy L. Thompson }
3387a982d89SJeremy L. Thompson 
3397a982d89SJeremy L. Thompson /**
34049fd234cSJeremy L Thompson 
341ca94c3ddSJeremy L Thompson   @brief Get the E-vector layout of a `CeedElemRestriction`
34249fd234cSJeremy L Thompson 
343ca94c3ddSJeremy L Thompson   @param[in]  rstr    `CeedElemRestriction`
344ca94c3ddSJeremy L Thompson   @param[out] layout  Variable to store layout array, stored as `[nodes, components, elements]`.
345ca94c3ddSJeremy L Thompson                         The data for node `i`, component `j`, element `k` in the E-vector is given by `i*layout[0] + j*layout[1] + k*layout[2]`.
34649fd234cSJeremy L Thompson 
34749fd234cSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
34849fd234cSJeremy L Thompson 
34949fd234cSJeremy L Thompson   @ref Backend
35049fd234cSJeremy L Thompson **/
3512b730f8bSJeremy L Thompson int CeedElemRestrictionGetELayout(CeedElemRestriction rstr, CeedInt (*layout)[3]) {
352ca94c3ddSJeremy L Thompson   CeedCheck(rstr->layout[0], rstr->ceed, CEED_ERROR_MINOR, "CeedElemRestriction has no layout data");
3532b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < 3; i++) (*layout)[i] = rstr->layout[i];
354e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
35549fd234cSJeremy L Thompson }
35649fd234cSJeremy L Thompson 
35749fd234cSJeremy L Thompson /**
35849fd234cSJeremy L Thompson 
359ca94c3ddSJeremy L Thompson   @brief Set the E-vector layout of a `CeedElemRestriction`
36049fd234cSJeremy L Thompson 
361ca94c3ddSJeremy L Thompson   @param[in] rstr   `CeedElemRestriction`
362ca94c3ddSJeremy L Thompson   @param[in] layout Variable to containing layout array, stored as `[nodes, components, elements]`.
363ca94c3ddSJeremy L Thompson                       The data for node `i`, component `j`, element `k` in the E-vector is given by `i*layout[0] + j*layout[1] + k*layout[2]`.
36449fd234cSJeremy L Thompson 
36549fd234cSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
36649fd234cSJeremy L Thompson 
36749fd234cSJeremy L Thompson   @ref Backend
36849fd234cSJeremy L Thompson **/
3692b730f8bSJeremy L Thompson int CeedElemRestrictionSetELayout(CeedElemRestriction rstr, CeedInt layout[3]) {
3702b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < 3; i++) rstr->layout[i] = layout[i];
371e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
37249fd234cSJeremy L Thompson }
37349fd234cSJeremy L Thompson 
37449fd234cSJeremy L Thompson /**
375ca94c3ddSJeremy L Thompson   @brief Get the backend data of a `CeedElemRestriction`
3767a982d89SJeremy L. Thompson 
377ca94c3ddSJeremy L Thompson   @param[in]  rstr `CeedElemRestriction`
3787a982d89SJeremy L. Thompson   @param[out] data Variable to store data
3797a982d89SJeremy L. Thompson 
3807a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3817a982d89SJeremy L. Thompson 
3827a982d89SJeremy L. Thompson   @ref Backend
3837a982d89SJeremy L. Thompson **/
384777ff853SJeremy L Thompson int CeedElemRestrictionGetData(CeedElemRestriction rstr, void *data) {
385777ff853SJeremy L Thompson   *(void **)data = rstr->data;
386e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3877a982d89SJeremy L. Thompson }
3887a982d89SJeremy L. Thompson 
3897a982d89SJeremy L. Thompson /**
390ca94c3ddSJeremy L Thompson   @brief Set the backend data of a `CeedElemRestriction`
3917a982d89SJeremy L. Thompson 
392ca94c3ddSJeremy L Thompson   @param[in,out] rstr `CeedElemRestriction`
393ea61e9acSJeremy L Thompson   @param[in]     data Data to set
3947a982d89SJeremy L. Thompson 
3957a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3967a982d89SJeremy L. Thompson 
3977a982d89SJeremy L. Thompson   @ref Backend
3987a982d89SJeremy L. Thompson **/
399777ff853SJeremy L Thompson int CeedElemRestrictionSetData(CeedElemRestriction rstr, void *data) {
400777ff853SJeremy L Thompson   rstr->data = data;
401e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4027a982d89SJeremy L. Thompson }
4037a982d89SJeremy L. Thompson 
40434359f16Sjeremylt /**
405ca94c3ddSJeremy L Thompson   @brief Increment the reference counter for a `CeedElemRestriction`
40634359f16Sjeremylt 
407ca94c3ddSJeremy L Thompson   @param[in,out] rstr `CeedElemRestriction` to increment the reference counter
40834359f16Sjeremylt 
40934359f16Sjeremylt   @return An error code: 0 - success, otherwise - failure
41034359f16Sjeremylt 
41134359f16Sjeremylt   @ref Backend
41234359f16Sjeremylt **/
4139560d06aSjeremylt int CeedElemRestrictionReference(CeedElemRestriction rstr) {
41434359f16Sjeremylt   rstr->ref_count++;
41534359f16Sjeremylt   return CEED_ERROR_SUCCESS;
41634359f16Sjeremylt }
41734359f16Sjeremylt 
4186e15d496SJeremy L Thompson /**
419ca94c3ddSJeremy L Thompson   @brief Estimate number of FLOPs required to apply `CeedElemRestriction` in `t_mode`
4206e15d496SJeremy L Thompson 
421ca94c3ddSJeremy L Thompson   @param[in]  rstr   `CeedElemRestriction` to estimate FLOPs for
422ea61e9acSJeremy L Thompson   @param[in]  t_mode Apply restriction or transpose
423ea61e9acSJeremy L Thompson   @param[out] flops  Address of variable to hold FLOPs estimate
4246e15d496SJeremy L Thompson 
4256e15d496SJeremy L Thompson   @ref Backend
4266e15d496SJeremy L Thompson **/
4272b730f8bSJeremy L Thompson int CeedElemRestrictionGetFlopsEstimate(CeedElemRestriction rstr, CeedTransposeMode t_mode, CeedSize *flops) {
428e7f679fcSJeremy L Thompson   CeedInt             e_size = rstr->num_block * rstr->block_size * rstr->elem_size * rstr->num_comp, scale = 0;
42989edb9e3SSebastian Grimberg   CeedRestrictionType rstr_type;
4301c66c397SJeremy L Thompson 
43189edb9e3SSebastian Grimberg   CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type));
4323ac8f562SJeremy L Thompson   if (rstr_type == CEED_RESTRICTION_POINTS) e_size = rstr->num_points * rstr->num_comp;
43377d1c127SSebastian Grimberg   if (t_mode == CEED_TRANSPOSE) {
43489edb9e3SSebastian Grimberg     switch (rstr_type) {
4353ac8f562SJeremy L Thompson       case CEED_RESTRICTION_POINTS:
4363ac8f562SJeremy L Thompson         scale = 0;
4373ac8f562SJeremy L Thompson         break;
43889edb9e3SSebastian Grimberg       case CEED_RESTRICTION_STRIDED:
43989edb9e3SSebastian Grimberg       case CEED_RESTRICTION_STANDARD:
44077d1c127SSebastian Grimberg         scale = 1;
44189edb9e3SSebastian Grimberg         break;
44289edb9e3SSebastian Grimberg       case CEED_RESTRICTION_ORIENTED:
44377d1c127SSebastian Grimberg         scale = 2;
44489edb9e3SSebastian Grimberg         break;
44589edb9e3SSebastian Grimberg       case CEED_RESTRICTION_CURL_ORIENTED:
44677d1c127SSebastian Grimberg         scale = 6;
44789edb9e3SSebastian Grimberg         break;
4486e15d496SJeremy L Thompson     }
44977d1c127SSebastian Grimberg   } else {
45089edb9e3SSebastian Grimberg     switch (rstr_type) {
45189edb9e3SSebastian Grimberg       case CEED_RESTRICTION_STRIDED:
45289edb9e3SSebastian Grimberg       case CEED_RESTRICTION_STANDARD:
4533ac8f562SJeremy L Thompson       case CEED_RESTRICTION_POINTS:
45477d1c127SSebastian Grimberg         scale = 0;
45589edb9e3SSebastian Grimberg         break;
45689edb9e3SSebastian Grimberg       case CEED_RESTRICTION_ORIENTED:
45777d1c127SSebastian Grimberg         scale = 1;
45889edb9e3SSebastian Grimberg         break;
45989edb9e3SSebastian Grimberg       case CEED_RESTRICTION_CURL_ORIENTED:
46077d1c127SSebastian Grimberg         scale = 5;
46189edb9e3SSebastian Grimberg         break;
46277d1c127SSebastian Grimberg     }
46377d1c127SSebastian Grimberg   }
4646e15d496SJeremy L Thompson   *flops = e_size * scale;
4656e15d496SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4666e15d496SJeremy L Thompson }
4676e15d496SJeremy L Thompson 
4687a982d89SJeremy L. Thompson /// @}
4697a982d89SJeremy L. Thompson 
47015910d16Sjeremylt /// @cond DOXYGEN_SKIP
47115910d16Sjeremylt static struct CeedElemRestriction_private ceed_elemrestriction_none;
47215910d16Sjeremylt /// @endcond
47315910d16Sjeremylt 
4747a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
4757a982d89SJeremy L. Thompson /// CeedElemRestriction Public API
4767a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
4777a982d89SJeremy L. Thompson /// @addtogroup CeedElemRestrictionUser
478d7b241e6Sjeremylt /// @{
479d7b241e6Sjeremylt 
4807a982d89SJeremy L. Thompson /// Indicate that the stride is determined by the backend
48145f1e315Sjeremylt const CeedInt CEED_STRIDES_BACKEND[3] = {0};
4827a982d89SJeremy L. Thompson 
483ca94c3ddSJeremy L Thompson /// Argument for @ref CeedOperatorSetField() indicating that the field does not require a `CeedElemRestriction`
4842b730f8bSJeremy L Thompson const CeedElemRestriction CEED_ELEMRESTRICTION_NONE = &ceed_elemrestriction_none;
4857a982d89SJeremy L. Thompson 
486d7b241e6Sjeremylt /**
487ca94c3ddSJeremy L Thompson   @brief Create a `CeedElemRestriction`
488d7b241e6Sjeremylt 
489ca94c3ddSJeremy L Thompson   @param[in]  ceed        `Ceed` context used to create the `CeedElemRestriction`
490ca94c3ddSJeremy L Thompson   @param[in]  num_elem    Number of elements described in the `offsets` array
491ea61e9acSJeremy L Thompson   @param[in]  elem_size   Size (number of "nodes") per element
492ea61e9acSJeremy L Thompson   @param[in]  num_comp    Number of field components per interpolation node (1 for scalar fields)
493fcbe8c06SSebastian Grimberg   @param[in]  comp_stride Stride between components for the same L-vector "node".
494ca94c3ddSJeremy L Thompson                             Data for node `i`, component `j`, element `k` can be found in the L-vector at index `offsets[i + k*elem_size] + j*comp_stride`.
495fcbe8c06SSebastian Grimberg   @param[in]  l_size      The size of the L-vector.
496fcbe8c06SSebastian Grimberg                             This vector may be larger than the elements and fields given by this restriction.
497ca94c3ddSJeremy L Thompson   @param[in]  mem_type    Memory type of the `offsets` array, see @ref CeedMemType
498ca94c3ddSJeremy L Thompson   @param[in]  copy_mode   Copy mode for the `offsets` array, see @ref CeedCopyMode
499ca94c3ddSJeremy L Thompson   @param[in]  offsets     Array of shape `[num_elem, elem_size]`.
500ca94c3ddSJeremy L Thompson                             Row `i` holds the ordered list of the offsets (into the input `CeedVector`) for the unknowns corresponding to element `i`, where 0 <= i < @a num_elem.
501ca94c3ddSJeremy L Thompson                             All offsets must be in the range `[0, l_size - 1]`.
502ca94c3ddSJeremy L Thompson   @param[out] rstr        Address of the variable where the newly created `CeedElemRestriction` will be stored
503d7b241e6Sjeremylt 
504b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
505dfdf5a53Sjeremylt 
5067a982d89SJeremy L. Thompson   @ref User
507b11c1e72Sjeremylt **/
5082b730f8bSJeremy L Thompson int CeedElemRestrictionCreate(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedInt comp_stride, CeedSize l_size,
5092b730f8bSJeremy L Thompson                               CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, CeedElemRestriction *rstr) {
5105fe0d4faSjeremylt   if (!ceed->ElemRestrictionCreate) {
5115fe0d4faSjeremylt     Ceed delegate;
5126574a04fSJeremy L Thompson 
5132b730f8bSJeremy L Thompson     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"));
514ca94c3ddSJeremy L Thompson     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreate");
5152b730f8bSJeremy L Thompson     CeedCall(CeedElemRestrictionCreate(delegate, num_elem, elem_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, rstr));
516e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
5175fe0d4faSjeremylt   }
5185fe0d4faSjeremylt 
519e7f679fcSJeremy L Thompson   CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative");
5206574a04fSJeremy L Thompson   CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1");
521ca94c3ddSJeremy L Thompson   CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component");
522ca94c3ddSJeremy L Thompson   CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction component stride must be at least 1");
523e022e1f8SJeremy L Thompson 
5242b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, rstr));
525db002c03SJeremy L Thompson   CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed));
526d1d35e2fSjeremylt   (*rstr)->ref_count   = 1;
527d1d35e2fSjeremylt   (*rstr)->num_elem    = num_elem;
528d1d35e2fSjeremylt   (*rstr)->elem_size   = elem_size;
529d1d35e2fSjeremylt   (*rstr)->num_comp    = num_comp;
530d1d35e2fSjeremylt   (*rstr)->comp_stride = comp_stride;
531d1d35e2fSjeremylt   (*rstr)->l_size      = l_size;
53205fa913cSJeremy L Thompson   (*rstr)->e_size      = num_elem * elem_size * num_comp;
533e7f679fcSJeremy L Thompson   (*rstr)->num_block   = num_elem;
534e7f679fcSJeremy L Thompson   (*rstr)->block_size  = 1;
53561a27d74SSebastian Grimberg   (*rstr)->rstr_type   = CEED_RESTRICTION_STANDARD;
536fcbe8c06SSebastian Grimberg   CeedCall(ceed->ElemRestrictionCreate(mem_type, copy_mode, offsets, NULL, NULL, *rstr));
537e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
538d7b241e6Sjeremylt }
539d7b241e6Sjeremylt 
540d7b241e6Sjeremylt /**
541ca94c3ddSJeremy L Thompson   @brief Create a `CeedElemRestriction` with orientation signs
542fc0567d9Srezgarshakeri 
543ca94c3ddSJeremy L Thompson   @param[in]  ceed        `Ceed` context used to create the `CeedElemRestriction`
544ca94c3ddSJeremy L Thompson   @param[in]  num_elem    Number of elements described in the `offsets` array
545ea61e9acSJeremy L Thompson   @param[in]  elem_size   Size (number of "nodes") per element
546ea61e9acSJeremy L Thompson   @param[in]  num_comp    Number of field components per interpolation node (1 for scalar fields)
547fcbe8c06SSebastian Grimberg   @param[in]  comp_stride Stride between components for the same L-vector "node".
548ca94c3ddSJeremy L Thompson                             Data for node `i`, component `j`, element `k` can be found in the L-vector at index `offsets[i + k*elem_size] + j*comp_stride`.
549fcbe8c06SSebastian Grimberg   @param[in]  l_size      The size of the L-vector.
550fcbe8c06SSebastian Grimberg                             This vector may be larger than the elements and fields given by this restriction.
551ca94c3ddSJeremy L Thompson   @param[in]  mem_type    Memory type of the `offsets` array, see @ref CeedMemType
552ca94c3ddSJeremy L Thompson   @param[in]  copy_mode   Copy mode for the `offsets` array, see @ref CeedCopyMode
553ca94c3ddSJeremy L Thompson   @param[in]  offsets     Array of shape `[num_elem, elem_size]`.
554ca94c3ddSJeremy L Thompson                             Row i holds the ordered list of the offsets (into the input `CeedVector`) for the unknowns corresponding to element `i`, where `0 <= i < num_elem`.
555ca94c3ddSJeremy L Thompson                             All offsets must be in the range `[0, l_size - 1]`.
556ca94c3ddSJeremy L Thompson   @param[in]  orients     Boolean array of shape `[num_elem, elem_size]` with `false` for positively oriented and `true` to flip the orientation
557ca94c3ddSJeremy L Thompson   @param[out] rstr        Address of the variable where the newly created `CeedElemRestriction` will be stored
558fc0567d9Srezgarshakeri 
559fc0567d9Srezgarshakeri   @return An error code: 0 - success, otherwise - failure
560fc0567d9Srezgarshakeri 
561fc0567d9Srezgarshakeri   @ref User
562fc0567d9Srezgarshakeri **/
5632b730f8bSJeremy L Thompson int CeedElemRestrictionCreateOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedInt comp_stride, CeedSize l_size,
56477d1c127SSebastian Grimberg                                       CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, const bool *orients,
565fc0567d9Srezgarshakeri                                       CeedElemRestriction *rstr) {
566fcbe8c06SSebastian Grimberg   if (!ceed->ElemRestrictionCreate) {
567fc0567d9Srezgarshakeri     Ceed delegate;
5686574a04fSJeremy L Thompson 
5692b730f8bSJeremy L Thompson     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"));
570ca94c3ddSJeremy L Thompson     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateOriented");
5712b730f8bSJeremy L Thompson     CeedCall(
57277d1c127SSebastian Grimberg         CeedElemRestrictionCreateOriented(delegate, num_elem, elem_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, orients, rstr));
573fc0567d9Srezgarshakeri     return CEED_ERROR_SUCCESS;
574fc0567d9Srezgarshakeri   }
575fc0567d9Srezgarshakeri 
576e7f679fcSJeremy L Thompson   CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative");
5776574a04fSJeremy L Thompson   CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1");
578ca94c3ddSJeremy L Thompson   CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component");
579ca94c3ddSJeremy L Thompson   CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction component stride must be at least 1");
580e022e1f8SJeremy L Thompson 
5812b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, rstr));
582db002c03SJeremy L Thompson   CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed));
583fc0567d9Srezgarshakeri   (*rstr)->ref_count   = 1;
584fc0567d9Srezgarshakeri   (*rstr)->num_elem    = num_elem;
585fc0567d9Srezgarshakeri   (*rstr)->elem_size   = elem_size;
586fc0567d9Srezgarshakeri   (*rstr)->num_comp    = num_comp;
587fc0567d9Srezgarshakeri   (*rstr)->comp_stride = comp_stride;
588fc0567d9Srezgarshakeri   (*rstr)->l_size      = l_size;
58905fa913cSJeremy L Thompson   (*rstr)->e_size      = num_elem * elem_size * num_comp;
590e7f679fcSJeremy L Thompson   (*rstr)->num_block   = num_elem;
591e7f679fcSJeremy L Thompson   (*rstr)->block_size  = 1;
592fcbe8c06SSebastian Grimberg   (*rstr)->rstr_type   = CEED_RESTRICTION_ORIENTED;
593fcbe8c06SSebastian Grimberg   CeedCall(ceed->ElemRestrictionCreate(mem_type, copy_mode, offsets, orients, NULL, *rstr));
59477d1c127SSebastian Grimberg   return CEED_ERROR_SUCCESS;
59577d1c127SSebastian Grimberg }
59677d1c127SSebastian Grimberg 
59777d1c127SSebastian Grimberg /**
598ca94c3ddSJeremy L Thompson   @brief Create a `CeedElemRestriction` with a general tridiagonal transformation matrix for curl-conforming elements
59977d1c127SSebastian Grimberg 
600ca94c3ddSJeremy L Thompson   @param[in]  ceed         `Ceed` context used to create the `CeedElemRestriction`
601ca94c3ddSJeremy L Thompson   @param[in]  num_elem     Number of elements described in the `offsets` array
60277d1c127SSebastian Grimberg   @param[in]  elem_size    Size (number of "nodes") per element
60377d1c127SSebastian Grimberg   @param[in]  num_comp     Number of field components per interpolation node (1 for scalar fields)
604fcbe8c06SSebastian Grimberg   @param[in]  comp_stride  Stride between components for the same L-vector "node".
605ca94c3ddSJeremy L Thompson                              Data for node `i`, component `j`, element `k` can be found in the L-vector at index `offsets[i + k*elem_size] + j*comp_stride`.
606fcbe8c06SSebastian Grimberg   @param[in]  l_size       The size of the L-vector.
607fcbe8c06SSebastian Grimberg                              This vector may be larger than the elements and fields given by this restriction.
608ca94c3ddSJeremy L Thompson   @param[in]  mem_type     Memory type of the `offsets` array, see @ref CeedMemType
609ca94c3ddSJeremy L Thompson   @param[in]  copy_mode    Copy mode for the `offsets` array, see @ref CeedCopyMode
610ca94c3ddSJeremy L Thompson   @param[in]  offsets      Array of shape `[num_elem, elem_size]`.
611ca94c3ddSJeremy L Thompson                              Row `i` holds the ordered list of the offsets (into the input `CeedVector`) for the unknowns corresponding to element `i`, where `0 <= i < num_elem`.
612ca94c3ddSJeremy L Thompson                              All offsets must be in the range `[0, l_size - 1]`.
613ca94c3ddSJeremy L Thompson   @param[in]  curl_orients Array of shape `[num_elem, 3 * elem_size]` representing a row-major tridiagonal matrix (`curl_orients[i * 3 * elem_size] = curl_orients[(i + 1) * 3 * elem_size - 1] = 0`, where `0 <= i < num_elem`) which is applied to the element unknowns upon restriction.
614ca94c3ddSJeremy L Thompson                              This orientation matrix allows for pairs of face degrees of freedom on elements for \f$H(\mathrm{curl})\f$ spaces to be coupled in the element restriction operation, which is a way to resolve face orientation issues for 3D meshes (https://dl.acm.org/doi/pdf/10.1145/3524456).
615ca94c3ddSJeremy L Thompson   @param[out] rstr         Address of the variable where the newly created `CeedElemRestriction` will be stored
61677d1c127SSebastian Grimberg 
61777d1c127SSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
61877d1c127SSebastian Grimberg 
61977d1c127SSebastian Grimberg   @ref User
62077d1c127SSebastian Grimberg **/
62177d1c127SSebastian Grimberg int CeedElemRestrictionCreateCurlOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedInt comp_stride, CeedSize l_size,
6220c73c039SSebastian Grimberg                                           CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, const CeedInt8 *curl_orients,
62377d1c127SSebastian Grimberg                                           CeedElemRestriction *rstr) {
624fcbe8c06SSebastian Grimberg   if (!ceed->ElemRestrictionCreate) {
62577d1c127SSebastian Grimberg     Ceed delegate;
62677d1c127SSebastian Grimberg 
62777d1c127SSebastian Grimberg     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"));
628ca94c3ddSJeremy L Thompson     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateCurlOriented");
62977d1c127SSebastian Grimberg     CeedCall(CeedElemRestrictionCreateCurlOriented(delegate, num_elem, elem_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets,
63077d1c127SSebastian Grimberg                                                    curl_orients, rstr));
63177d1c127SSebastian Grimberg     return CEED_ERROR_SUCCESS;
63277d1c127SSebastian Grimberg   }
63377d1c127SSebastian Grimberg 
634e7f679fcSJeremy L Thompson   CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative");
63577d1c127SSebastian Grimberg   CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1");
636ca94c3ddSJeremy L Thompson   CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component");
637ca94c3ddSJeremy L Thompson   CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction component stride must be at least 1");
63877d1c127SSebastian Grimberg 
63977d1c127SSebastian Grimberg   CeedCall(CeedCalloc(1, rstr));
640fcbe8c06SSebastian Grimberg   CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed));
64177d1c127SSebastian Grimberg   (*rstr)->ref_count   = 1;
64277d1c127SSebastian Grimberg   (*rstr)->num_elem    = num_elem;
64377d1c127SSebastian Grimberg   (*rstr)->elem_size   = elem_size;
64477d1c127SSebastian Grimberg   (*rstr)->num_comp    = num_comp;
64577d1c127SSebastian Grimberg   (*rstr)->comp_stride = comp_stride;
64677d1c127SSebastian Grimberg   (*rstr)->l_size      = l_size;
64705fa913cSJeremy L Thompson   (*rstr)->e_size      = num_elem * elem_size * num_comp;
648e7f679fcSJeremy L Thompson   (*rstr)->num_block   = num_elem;
649e7f679fcSJeremy L Thompson   (*rstr)->block_size  = 1;
650fcbe8c06SSebastian Grimberg   (*rstr)->rstr_type   = CEED_RESTRICTION_CURL_ORIENTED;
651fcbe8c06SSebastian Grimberg   CeedCall(ceed->ElemRestrictionCreate(mem_type, copy_mode, offsets, NULL, curl_orients, *rstr));
652fc0567d9Srezgarshakeri   return CEED_ERROR_SUCCESS;
653fc0567d9Srezgarshakeri }
654fc0567d9Srezgarshakeri 
655fc0567d9Srezgarshakeri /**
656ca94c3ddSJeremy L Thompson   @brief Create a strided `CeedElemRestriction`
657d7b241e6Sjeremylt 
658ca94c3ddSJeremy L Thompson   @param[in]  ceed      `Ceed` context used to create the `CeedElemRestriction`
659ea61e9acSJeremy L Thompson   @param[in]  num_elem  Number of elements described by the restriction
660ea61e9acSJeremy L Thompson   @param[in]  elem_size Size (number of "nodes") per element
661ea61e9acSJeremy L Thompson   @param[in]  num_comp  Number of field components per interpolation "node" (1 for scalar fields)
662fcbe8c06SSebastian Grimberg   @param[in]  l_size    The size of the L-vector.
663fcbe8c06SSebastian Grimberg                           This vector may be larger than the elements and fields given by this restriction.
664ca94c3ddSJeremy L Thompson   @param[in]  strides   Array for strides between `[nodes, components, elements]`.
665ca94c3ddSJeremy L Thompson                           Data for node `i`, component `j`, element `k` can be found in the L-vector at index `i*strides[0] + j*strides[1] + k*strides[2]`.
666ca94c3ddSJeremy L Thompson                           @ref CEED_STRIDES_BACKEND may be used for `CeedVector` ordered by the same `Ceed` backend.
667ca94c3ddSJeremy L Thompson   @param[out] rstr      Address of the variable where the newly created `CeedElemRestriction` will be stored
668d7b241e6Sjeremylt 
669b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
670dfdf5a53Sjeremylt 
6717a982d89SJeremy L. Thompson   @ref User
672b11c1e72Sjeremylt **/
6732b730f8bSJeremy L Thompson int CeedElemRestrictionCreateStrided(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedSize l_size, const CeedInt strides[3],
674f90c8643Sjeremylt                                      CeedElemRestriction *rstr) {
6755fe0d4faSjeremylt   if (!ceed->ElemRestrictionCreate) {
6765fe0d4faSjeremylt     Ceed delegate;
677b04eb3d9SSebastian Grimberg 
6782b730f8bSJeremy L Thompson     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"));
679ca94c3ddSJeremy L Thompson     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateStrided");
6802b730f8bSJeremy L Thompson     CeedCall(CeedElemRestrictionCreateStrided(delegate, num_elem, elem_size, num_comp, l_size, strides, rstr));
681e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
6825fe0d4faSjeremylt   }
6835fe0d4faSjeremylt 
684e7f679fcSJeremy L Thompson   CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative");
6856574a04fSJeremy L Thompson   CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1");
686ca94c3ddSJeremy L Thompson   CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component");
687e7f679fcSJeremy L Thompson   CeedCheck(l_size >= num_elem * elem_size * num_comp, ceed, CEED_ERROR_DIMENSION, "L-vector size must be at least num_elem * elem_size * num_comp");
688e022e1f8SJeremy L Thompson 
6892b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, rstr));
690db002c03SJeremy L Thompson   CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed));
691d1d35e2fSjeremylt   (*rstr)->ref_count  = 1;
692d1d35e2fSjeremylt   (*rstr)->num_elem   = num_elem;
693d1d35e2fSjeremylt   (*rstr)->elem_size  = elem_size;
694d1d35e2fSjeremylt   (*rstr)->num_comp   = num_comp;
695d1d35e2fSjeremylt   (*rstr)->l_size     = l_size;
69605fa913cSJeremy L Thompson   (*rstr)->e_size     = num_elem * elem_size * num_comp;
697e7f679fcSJeremy L Thompson   (*rstr)->num_block  = num_elem;
698e7f679fcSJeremy L Thompson   (*rstr)->block_size = 1;
699fcbe8c06SSebastian Grimberg   (*rstr)->rstr_type  = CEED_RESTRICTION_STRIDED;
7002b730f8bSJeremy L Thompson   CeedCall(CeedMalloc(3, &(*rstr)->strides));
7012b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < 3; i++) (*rstr)->strides[i] = strides[i];
702fcbe8c06SSebastian Grimberg   CeedCall(ceed->ElemRestrictionCreate(CEED_MEM_HOST, CEED_OWN_POINTER, NULL, NULL, NULL, *rstr));
703e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
704d7b241e6Sjeremylt }
705d7b241e6Sjeremylt 
706d7b241e6Sjeremylt /**
707ca94c3ddSJeremy L Thompson   @brief Create a points `CeedElemRestriction`, for restricting for restricting from a all local points to the current element in which they are located.
7083ac8f562SJeremy L Thompson 
7093ac8f562SJeremy L Thompson   The offsets array is arranged as
7103ac8f562SJeremy L Thompson 
7113ac8f562SJeremy L Thompson   element_0_start_index
7123ac8f562SJeremy L Thompson   element_1_start_index
7133ac8f562SJeremy L Thompson   ...
7143ac8f562SJeremy L Thompson   element_n_start_index
7153ac8f562SJeremy L Thompson   element_n_stop_index
7163ac8f562SJeremy L Thompson   element_0_point_0
7173ac8f562SJeremy L Thompson   element_0_point_1
7183ac8f562SJeremy L Thompson   ...
7193ac8f562SJeremy L Thompson 
720ca94c3ddSJeremy L Thompson   @param[in]  ceed       `Ceed` context used to create the `CeedElemRestriction`
721ca94c3ddSJeremy L Thompson   @param[in]  num_elem   Number of elements described in the `offsets` array
722ca94c3ddSJeremy L Thompson   @param[in]  num_points Number of points described in the `offsets` array
7233ac8f562SJeremy L Thompson   @param[in]  num_comp   Number of field components per interpolation node (1 for scalar fields).
7243ac8f562SJeremy L Thompson                            Components are assumed to be contiguous by point.
7253ac8f562SJeremy L Thompson   @param[in]  l_size     The size of the L-vector.
7263ac8f562SJeremy L Thompson                            This vector may be larger than the elements and fields given by this restriction.
727ca94c3ddSJeremy L Thompson   @param[in]  mem_type   Memory type of the `offsets` array, see @ref CeedMemType
728ca94c3ddSJeremy L Thompson   @param[in]  copy_mode  Copy mode for the `offsets` array, see @ref CeedCopyMode
729ca94c3ddSJeremy L Thompson   @param[in]  offsets    Array of size `num_elem + 1 + num_points`.
7303ac8f562SJeremy L Thompson                            The first portion of the offsets array holds the ranges of indices corresponding to each element.
7313ac8f562SJeremy L Thompson                            The second portion holds the indices for each element.
732ca94c3ddSJeremy L Thompson   @param[out] rstr       Address of the variable where the newly created `CeedElemRestriction` will be stored
7333ac8f562SJeremy L Thompson 
7343ac8f562SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
7353ac8f562SJeremy L Thompson 
7363ac8f562SJeremy L Thompson   @ref Backend
7373ac8f562SJeremy L Thompson  **/
7383ac8f562SJeremy L Thompson int CeedElemRestrictionCreateAtPoints(Ceed ceed, CeedInt num_elem, CeedInt num_points, CeedInt num_comp, CeedSize l_size, CeedMemType mem_type,
7393ac8f562SJeremy L Thompson                                       CeedCopyMode copy_mode, const CeedInt *offsets, CeedElemRestriction *rstr) {
7403ac8f562SJeremy L Thompson   if (!ceed->ElemRestrictionCreateAtPoints) {
7413ac8f562SJeremy L Thompson     Ceed delegate;
7423ac8f562SJeremy L Thompson 
7433ac8f562SJeremy L Thompson     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"));
744ca94c3ddSJeremy L Thompson     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateAtPoints");
7453ac8f562SJeremy L Thompson     CeedCall(CeedElemRestrictionCreateAtPoints(delegate, num_elem, num_points, num_comp, l_size, mem_type, copy_mode, offsets, rstr));
7463ac8f562SJeremy L Thompson     return CEED_ERROR_SUCCESS;
7473ac8f562SJeremy L Thompson   }
7483ac8f562SJeremy L Thompson 
7493ac8f562SJeremy L Thompson   CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative");
7503ac8f562SJeremy L Thompson   CeedCheck(num_points >= 0, ceed, CEED_ERROR_DIMENSION, "Number of points must be non-negative");
751ca94c3ddSJeremy L Thompson   CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component");
7523ac8f562SJeremy L Thompson   CeedCheck(l_size >= num_points * num_comp, ceed, CEED_ERROR_DIMENSION, "L-vector must be at least num_points * num_comp");
7533ac8f562SJeremy L Thompson 
7543ac8f562SJeremy L Thompson   CeedCall(CeedCalloc(1, rstr));
7553ac8f562SJeremy L Thompson   CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed));
7563ac8f562SJeremy L Thompson   (*rstr)->ref_count  = 1;
7573ac8f562SJeremy L Thompson   (*rstr)->num_elem   = num_elem;
7583ac8f562SJeremy L Thompson   (*rstr)->num_points = num_points;
7593ac8f562SJeremy L Thompson   (*rstr)->num_comp   = num_comp;
7603ac8f562SJeremy L Thompson   (*rstr)->l_size     = l_size;
76105fa913cSJeremy L Thompson   (*rstr)->e_size     = num_points * num_comp;
76205fa913cSJeremy L Thompson   (*rstr)->num_block  = num_elem;
7633ac8f562SJeremy L Thompson   (*rstr)->block_size = 1;
7643ac8f562SJeremy L Thompson   (*rstr)->rstr_type  = CEED_RESTRICTION_POINTS;
7653ac8f562SJeremy L Thompson   CeedCall(ceed->ElemRestrictionCreateAtPoints(mem_type, copy_mode, offsets, NULL, NULL, *rstr));
7663ac8f562SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7673ac8f562SJeremy L Thompson }
7683ac8f562SJeremy L Thompson 
7693ac8f562SJeremy L Thompson /**
770ca94c3ddSJeremy L Thompson   @brief Create a blocked `CeedElemRestriction`, typically only used by backends
771d7b241e6Sjeremylt 
772ca94c3ddSJeremy L Thompson   @param[in]  ceed        `Ceed` context used to create the `CeedElemRestriction`
773ca94c3ddSJeremy L Thompson   @param[in]  num_elem    Number of elements described in the `offsets` array
774ea61e9acSJeremy L Thompson   @param[in]  elem_size   Size (number of unknowns) per element
775e7f679fcSJeremy L Thompson   @param[in]  block_size  Number of elements in a block
776ea61e9acSJeremy L Thompson   @param[in]  num_comp    Number of field components per interpolation node (1 for scalar fields)
777fcbe8c06SSebastian Grimberg   @param[in]  comp_stride Stride between components for the same L-vector "node".
778ca94c3ddSJeremy L Thompson                             Data for node `i`, component `j`, element `k` can be found in the L-vector at index `offsets[i + k*elem_size] + j*comp_stride`.
779fcbe8c06SSebastian Grimberg   @param[in]  l_size      The size of the L-vector.
780fcbe8c06SSebastian Grimberg                             This vector may be larger than the elements and fields given by this restriction.
781ca94c3ddSJeremy L Thompson   @param[in]  mem_type    Memory type of the `offsets` array, see @ref CeedMemType
782ca94c3ddSJeremy L Thompson   @param[in]  copy_mode   Copy mode for the `offsets` array, see @ref CeedCopyMode
783ca94c3ddSJeremy L Thompson   @param[in]  offsets     Array of shape `[num_elem, elem_size]`.
784ca94c3ddSJeremy L Thompson                             Row `i` holds the ordered list of the offsets (into the input `CeedVector`) for the unknowns corresponding to element `i`, where `0 <= i < num_elem`.
785ca94c3ddSJeremy L Thompson                             All offsets must be in the range `[0, l_size - 1]`.
786ca94c3ddSJeremy L Thompson                             The backend will permute and pad this array to the desired ordering for the blocksize, which is typically given by the backend.
787ca94c3ddSJeremy L Thompson                             The default reordering is to interlace elements.
788ca94c3ddSJeremy L Thompson   @param[out] rstr        Address of the variable where the newly created `CeedElemRestriction` will be stored
789d7b241e6Sjeremylt 
790b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
791dfdf5a53Sjeremylt 
7927a982d89SJeremy L. Thompson   @ref Backend
793b11c1e72Sjeremylt  **/
794e7f679fcSJeremy L Thompson int CeedElemRestrictionCreateBlocked(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt block_size, CeedInt num_comp, CeedInt comp_stride,
7952b730f8bSJeremy L Thompson                                      CeedSize l_size, CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets,
7964ce2993fSjeremylt                                      CeedElemRestriction *rstr) {
7971c66c397SJeremy L Thompson   CeedInt *block_offsets, num_block = (num_elem / block_size) + !!(num_elem % block_size);
798d7b241e6Sjeremylt 
7995fe0d4faSjeremylt   if (!ceed->ElemRestrictionCreateBlocked) {
8005fe0d4faSjeremylt     Ceed delegate;
8016574a04fSJeremy L Thompson 
8022b730f8bSJeremy L Thompson     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"));
803ca94c3ddSJeremy L Thompson     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateBlocked");
804e7f679fcSJeremy L Thompson     CeedCall(CeedElemRestrictionCreateBlocked(delegate, num_elem, elem_size, block_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets,
805e7f679fcSJeremy L Thompson                                               rstr));
806e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
8075fe0d4faSjeremylt   }
808d7b241e6Sjeremylt 
809e7f679fcSJeremy L Thompson   CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative");
8106574a04fSJeremy L Thompson   CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1");
811e7f679fcSJeremy L Thompson   CeedCheck(block_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1");
812ca94c3ddSJeremy L Thompson   CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component");
813ca94c3ddSJeremy L Thompson   CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction component stride must be at least 1");
814e022e1f8SJeremy L Thompson 
815e7f679fcSJeremy L Thompson   CeedCall(CeedCalloc(num_block * block_size * elem_size, &block_offsets));
816e7f679fcSJeremy L Thompson   CeedCall(CeedPermutePadOffsets(offsets, block_offsets, num_block, num_elem, block_size, elem_size));
817d7b241e6Sjeremylt 
818db002c03SJeremy L Thompson   CeedCall(CeedCalloc(1, rstr));
819db002c03SJeremy L Thompson   CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed));
820d1d35e2fSjeremylt   (*rstr)->ref_count   = 1;
821d1d35e2fSjeremylt   (*rstr)->num_elem    = num_elem;
822d1d35e2fSjeremylt   (*rstr)->elem_size   = elem_size;
823d1d35e2fSjeremylt   (*rstr)->num_comp    = num_comp;
824d1d35e2fSjeremylt   (*rstr)->comp_stride = comp_stride;
825d1d35e2fSjeremylt   (*rstr)->l_size      = l_size;
82605fa913cSJeremy L Thompson   (*rstr)->e_size      = num_block * block_size * elem_size * num_comp;
827e7f679fcSJeremy L Thompson   (*rstr)->num_block   = num_block;
828e7f679fcSJeremy L Thompson   (*rstr)->block_size  = block_size;
82961a27d74SSebastian Grimberg   (*rstr)->rstr_type   = CEED_RESTRICTION_STANDARD;
830e7f679fcSJeremy L Thompson   CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, (const CeedInt *)block_offsets, NULL, NULL, *rstr));
8311c66c397SJeremy L Thompson   if (copy_mode == CEED_OWN_POINTER) CeedCall(CeedFree(&offsets));
832e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
833d7b241e6Sjeremylt }
834d7b241e6Sjeremylt 
835b11c1e72Sjeremylt /**
836ca94c3ddSJeremy L Thompson   @brief Create a blocked oriented `CeedElemRestriction`, typically only used by backends
83777d1c127SSebastian Grimberg 
838ca94c3ddSJeremy L Thompson   @param[in]  ceed        `Ceed` context used to create the `CeedElemRestriction`
839ca94c3ddSJeremy L Thompson   @param[in]  num_elem    Number of elements described in the `offsets` array.
84077d1c127SSebastian Grimberg   @param[in]  elem_size   Size (number of unknowns) per element
841e7f679fcSJeremy L Thompson   @param[in]  block_size  Number of elements in a block
84277d1c127SSebastian Grimberg   @param[in]  num_comp    Number of field components per interpolation node (1 for scalar fields)
843fcbe8c06SSebastian Grimberg   @param[in]  comp_stride Stride between components for the same L-vector "node".
844ca94c3ddSJeremy L Thompson                             Data for node `i`, component `j`, element `k` can be found in the L-vector at index `offsets[i + k*elem_size] + j*comp_stride`.
845fcbe8c06SSebastian Grimberg   @param[in]  l_size      The size of the L-vector.
846fcbe8c06SSebastian Grimberg                             This vector may be larger than the elements and fields given by this restriction.
847ca94c3ddSJeremy L Thompson   @param[in]  mem_type    Memory type of the `offsets` array, see @ref CeedMemType
848ca94c3ddSJeremy L Thompson   @param[in]  copy_mode   Copy mode for the `offsets` array, see @ref CeedCopyMode
849ca94c3ddSJeremy L Thompson   @param[in]  offsets     Array of shape `[num_elem, elem_size]`.
850ca94c3ddSJeremy L Thompson                             Row `i` holds the ordered list of the offsets (into the input `CeedVector`) for the unknowns corresponding to element `i`, where `0 <= i < num_elem`.
851ca94c3ddSJeremy L Thompson                             All offsets must be in the range `[0, l_size - 1]`.
852ca94c3ddSJeremy L Thompson                             The backend will permute and pad this array to the desired ordering for the blocksize, which is typically given by the backend.
853ca94c3ddSJeremy L Thompson                             The default reordering is to interlace elements.
854ca94c3ddSJeremy L Thompson   @param[in]  orients     Boolean array of shape `[num_elem, elem_size]` with `false` for positively oriented and `true` to flip the orientation.
855ca94c3ddSJeremy L Thompson                             Will also be permuted and padded similarly to `offsets`.
856ca94c3ddSJeremy L Thompson   @param[out] rstr        Address of the variable where the newly created `CeedElemRestriction` will be stored
85777d1c127SSebastian Grimberg 
85877d1c127SSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
85977d1c127SSebastian Grimberg 
86077d1c127SSebastian Grimberg   @ref Backend
86177d1c127SSebastian Grimberg  **/
862e7f679fcSJeremy L Thompson int CeedElemRestrictionCreateBlockedOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt block_size, CeedInt num_comp,
863e7f679fcSJeremy L Thompson                                              CeedInt comp_stride, CeedSize l_size, CeedMemType mem_type, CeedCopyMode copy_mode,
864e7f679fcSJeremy L Thompson                                              const CeedInt *offsets, const bool *orients, CeedElemRestriction *rstr) {
865e7f679fcSJeremy L Thompson   bool    *block_orients;
8661c66c397SJeremy L Thompson   CeedInt *block_offsets, num_block = (num_elem / block_size) + !!(num_elem % block_size);
86777d1c127SSebastian Grimberg 
868fcbe8c06SSebastian Grimberg   if (!ceed->ElemRestrictionCreateBlocked) {
86977d1c127SSebastian Grimberg     Ceed delegate;
87077d1c127SSebastian Grimberg 
87177d1c127SSebastian Grimberg     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"));
872ca94c3ddSJeremy L Thompson     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateBlockedOriented");
873e7f679fcSJeremy L Thompson     CeedCall(CeedElemRestrictionCreateBlockedOriented(delegate, num_elem, elem_size, block_size, num_comp, comp_stride, l_size, mem_type, copy_mode,
87477d1c127SSebastian Grimberg                                                       offsets, orients, rstr));
87577d1c127SSebastian Grimberg     return CEED_ERROR_SUCCESS;
87677d1c127SSebastian Grimberg   }
87777d1c127SSebastian Grimberg 
87877d1c127SSebastian Grimberg   CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1");
879e7f679fcSJeremy L Thompson   CeedCheck(block_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1");
880ca94c3ddSJeremy L Thompson   CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component");
881ca94c3ddSJeremy L Thompson   CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction component stride must be at least 1");
88277d1c127SSebastian Grimberg 
883e7f679fcSJeremy L Thompson   CeedCall(CeedCalloc(num_block * block_size * elem_size, &block_offsets));
884e7f679fcSJeremy L Thompson   CeedCall(CeedCalloc(num_block * block_size * elem_size, &block_orients));
885e7f679fcSJeremy L Thompson   CeedCall(CeedPermutePadOffsets(offsets, block_offsets, num_block, num_elem, block_size, elem_size));
886e7f679fcSJeremy L Thompson   CeedCall(CeedPermutePadOrients(orients, block_orients, num_block, num_elem, block_size, elem_size));
88777d1c127SSebastian Grimberg 
888fcbe8c06SSebastian Grimberg   CeedCall(CeedCalloc(1, rstr));
889fcbe8c06SSebastian Grimberg   CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed));
89077d1c127SSebastian Grimberg   (*rstr)->ref_count   = 1;
89177d1c127SSebastian Grimberg   (*rstr)->num_elem    = num_elem;
89277d1c127SSebastian Grimberg   (*rstr)->elem_size   = elem_size;
89377d1c127SSebastian Grimberg   (*rstr)->num_comp    = num_comp;
89477d1c127SSebastian Grimberg   (*rstr)->comp_stride = comp_stride;
89577d1c127SSebastian Grimberg   (*rstr)->l_size      = l_size;
89605fa913cSJeremy L Thompson   (*rstr)->e_size      = num_block * block_size * elem_size * num_comp;
897e7f679fcSJeremy L Thompson   (*rstr)->num_block   = num_block;
898e7f679fcSJeremy L Thompson   (*rstr)->block_size  = block_size;
899fcbe8c06SSebastian Grimberg   (*rstr)->rstr_type   = CEED_RESTRICTION_ORIENTED;
900e7f679fcSJeremy L Thompson   CeedCall(
901e7f679fcSJeremy L Thompson       ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, (const CeedInt *)block_offsets, (const bool *)block_orients, NULL, *rstr));
9021c66c397SJeremy L Thompson   if (copy_mode == CEED_OWN_POINTER) CeedCall(CeedFree(&offsets));
90377d1c127SSebastian Grimberg   return CEED_ERROR_SUCCESS;
90477d1c127SSebastian Grimberg }
90577d1c127SSebastian Grimberg 
90677d1c127SSebastian Grimberg /**
907ca94c3ddSJeremy L Thompson   @brief Create a blocked curl-oriented `CeedElemRestriction`, typically only used by backends
90877d1c127SSebastian Grimberg 
909ca94c3ddSJeremy L Thompson   @param[in]  ceed         `Ceed` context used to create the `CeedElemRestriction`
910ca94c3ddSJeremy L Thompson   @param[in]  num_elem     Number of elements described in the `offsets` array.
91177d1c127SSebastian Grimberg   @param[in]  elem_size    Size (number of unknowns) per element
912e7f679fcSJeremy L Thompson   @param[in]  block_size   Number of elements in a block
91377d1c127SSebastian Grimberg   @param[in]  num_comp     Number of field components per interpolation node (1 for scalar fields)
914fcbe8c06SSebastian Grimberg   @param[in]  comp_stride  Stride between components for the same L-vector "node".
915ca94c3ddSJeremy L Thompson                              Data for node `i`, component `j`, element `k` can be found in the L-vector at index `offsets[i + k*elem_size] + j*comp_stride`.
916fcbe8c06SSebastian Grimberg   @param[in]  l_size       The size of the L-vector.
917fcbe8c06SSebastian Grimberg                              This vector may be larger than the elements and fields given by this restriction.
918ca94c3ddSJeremy L Thompson   @param[in]  mem_type     Memory type of the `offsets` array, see @ref CeedMemType
919ca94c3ddSJeremy L Thompson   @param[in]  copy_mode    Copy mode for the `offsets` array, see @ref CeedCopyMode
920ca94c3ddSJeremy L Thompson   @param[in]  offsets      Array of shape `[num_elem, elem_size]`.
921ca94c3ddSJeremy L Thompson                              Row `i` holds the ordered list of the offsets (into the input `CeedVector`) for the unknowns corresponding to element `i`, where `0 <= i < num_elem`.
922ca94c3ddSJeremy L Thompson                              All offsets must be in the range `[0, l_size - 1]`.
923ca94c3ddSJeremy L Thompson                              The backend will permute and pad this array to the desired  ordering for the blocksize, which is typically given by the backend.
924ca94c3ddSJeremy L Thompson                              The default reordering is to interlace elements.
925ca94c3ddSJeremy L Thompson   @param[in]  curl_orients Array of shape `[num_elem, 3 * elem_size]` representing a row-major tridiagonal matrix (`curl_orients[i * 3 * elem_size] = curl_orients[(i + 1) * 3 * elem_size - 1] = 0`, where `0 <= i < num_elem`) which is applied to the element unknowns upon restriction.
926ca94c3ddSJeremy L Thompson                              This orientation matrix allows for pairs of face degrees of freedom on elements for \f$H(\mathrm{curl})\f$ spaces to be coupled in the element restriction  operation, which is a way to resolve face orientation issues for 3D meshes (https://dl.acm.org/doi/pdf/10.1145/3524456).
927ca94c3ddSJeremy L Thompson                              Will also be permuted and padded similarly to offsets.
928ca94c3ddSJeremy L Thompson   @param[out] rstr         Address of the variable where the newly created `CeedElemRestriction` will be stored
92977d1c127SSebastian Grimberg 
93077d1c127SSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
93177d1c127SSebastian Grimberg 
93277d1c127SSebastian Grimberg   @ref Backend
93377d1c127SSebastian Grimberg  **/
934e7f679fcSJeremy L Thompson int CeedElemRestrictionCreateBlockedCurlOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt block_size, CeedInt num_comp,
93577d1c127SSebastian Grimberg                                                  CeedInt comp_stride, CeedSize l_size, CeedMemType mem_type, CeedCopyMode copy_mode,
9360c73c039SSebastian Grimberg                                                  const CeedInt *offsets, const CeedInt8 *curl_orients, CeedElemRestriction *rstr) {
937e7f679fcSJeremy L Thompson   CeedInt8 *block_curl_orients;
9381c66c397SJeremy L Thompson   CeedInt  *block_offsets, num_block = (num_elem / block_size) + !!(num_elem % block_size);
93977d1c127SSebastian Grimberg 
940fcbe8c06SSebastian Grimberg   if (!ceed->ElemRestrictionCreateBlocked) {
94177d1c127SSebastian Grimberg     Ceed delegate;
94277d1c127SSebastian Grimberg 
94377d1c127SSebastian Grimberg     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"));
944ca94c3ddSJeremy L Thompson     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateBlockedCurlOriented");
945e7f679fcSJeremy L Thompson     CeedCall(CeedElemRestrictionCreateBlockedCurlOriented(delegate, num_elem, elem_size, block_size, num_comp, comp_stride, l_size, mem_type,
946e7f679fcSJeremy L Thompson                                                           copy_mode, offsets, curl_orients, rstr));
94777d1c127SSebastian Grimberg     return CEED_ERROR_SUCCESS;
94877d1c127SSebastian Grimberg   }
94977d1c127SSebastian Grimberg 
950e7f679fcSJeremy L Thompson   CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative");
95177d1c127SSebastian Grimberg   CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1");
952e7f679fcSJeremy L Thompson   CeedCheck(block_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1");
953ca94c3ddSJeremy L Thompson   CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component");
954ca94c3ddSJeremy L Thompson   CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction component stride must be at least 1");
95577d1c127SSebastian Grimberg 
956e7f679fcSJeremy L Thompson   CeedCall(CeedCalloc(num_block * block_size * elem_size, &block_offsets));
957e7f679fcSJeremy L Thompson   CeedCall(CeedCalloc(num_block * block_size * 3 * elem_size, &block_curl_orients));
958e7f679fcSJeremy L Thompson   CeedCall(CeedPermutePadOffsets(offsets, block_offsets, num_block, num_elem, block_size, elem_size));
959e7f679fcSJeremy L Thompson   CeedCall(CeedPermutePadCurlOrients(curl_orients, block_curl_orients, num_block, num_elem, block_size, 3 * elem_size));
96077d1c127SSebastian Grimberg 
961fcbe8c06SSebastian Grimberg   CeedCall(CeedCalloc(1, rstr));
962fcbe8c06SSebastian Grimberg   CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed));
96377d1c127SSebastian Grimberg   (*rstr)->ref_count   = 1;
96477d1c127SSebastian Grimberg   (*rstr)->num_elem    = num_elem;
96577d1c127SSebastian Grimberg   (*rstr)->elem_size   = elem_size;
96677d1c127SSebastian Grimberg   (*rstr)->num_comp    = num_comp;
96777d1c127SSebastian Grimberg   (*rstr)->comp_stride = comp_stride;
96877d1c127SSebastian Grimberg   (*rstr)->l_size      = l_size;
96905fa913cSJeremy L Thompson   (*rstr)->e_size      = num_block * block_size * elem_size * num_comp;
970e7f679fcSJeremy L Thompson   (*rstr)->num_block   = num_block;
971e7f679fcSJeremy L Thompson   (*rstr)->block_size  = block_size;
972fcbe8c06SSebastian Grimberg   (*rstr)->rstr_type   = CEED_RESTRICTION_CURL_ORIENTED;
973e7f679fcSJeremy L Thompson   CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, (const CeedInt *)block_offsets, NULL,
974e7f679fcSJeremy L Thompson                                               (const CeedInt8 *)block_curl_orients, *rstr));
9751c66c397SJeremy L Thompson   if (copy_mode == CEED_OWN_POINTER) CeedCall(CeedFree(&offsets));
97677d1c127SSebastian Grimberg   return CEED_ERROR_SUCCESS;
97777d1c127SSebastian Grimberg }
97877d1c127SSebastian Grimberg 
97977d1c127SSebastian Grimberg /**
980ca94c3ddSJeremy L Thompson   @brief Create a blocked strided `CeedElemRestriction`, typically only used by backends
9817509a596Sjeremylt 
982ca94c3ddSJeremy L Thompson   @param[in]  ceed        `Ceed` context used to create the `CeedElemRestriction`
983ea61e9acSJeremy L Thompson   @param[in]  num_elem    Number of elements described by the restriction
984ea61e9acSJeremy L Thompson   @param[in]  elem_size   Size (number of "nodes") per element
985e7f679fcSJeremy L Thompson   @param[in]  block_size  Number of elements in a block
986ea61e9acSJeremy L Thompson   @param[in]  num_comp    Number of field components per interpolation node (1 for scalar fields)
987fcbe8c06SSebastian Grimberg   @param[in]  l_size      The size of the L-vector.
988fcbe8c06SSebastian Grimberg                             This vector may be larger than the elements and fields given by this restriction.
989ca94c3ddSJeremy L Thompson   @param[in]  strides     Array for strides between `[nodes, components, elements]`.
990ca94c3ddSJeremy L Thompson                             Data for node `i`, component `j`, element `k` can be found in the L-vector at index `i*strides[0] + j*strides[1] +k*strides[2]`.
991ca94c3ddSJeremy L Thompson                             @ref CEED_STRIDES_BACKEND may be used for `CeedVector` ordered by the same `Ceed` backend.
992ca94c3ddSJeremy L Thompson   @param[out] rstr        Address of the variable where the newly created `CeedElemRestriction` will be stored
9937509a596Sjeremylt 
9947509a596Sjeremylt   @return An error code: 0 - success, otherwise - failure
9957509a596Sjeremylt 
9967a982d89SJeremy L. Thompson   @ref User
9977509a596Sjeremylt **/
998e7f679fcSJeremy L Thompson int CeedElemRestrictionCreateBlockedStrided(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt block_size, CeedInt num_comp, CeedSize l_size,
9998621c6c6SJeremy L Thompson                                             const CeedInt strides[3], CeedElemRestriction *rstr) {
1000e7f679fcSJeremy L Thompson   CeedInt num_block = (num_elem / block_size) + !!(num_elem % block_size);
10017509a596Sjeremylt 
10027509a596Sjeremylt   if (!ceed->ElemRestrictionCreateBlocked) {
10037509a596Sjeremylt     Ceed delegate;
10046574a04fSJeremy L Thompson 
10052b730f8bSJeremy L Thompson     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"));
1006ca94c3ddSJeremy L Thompson     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateBlockedStrided");
1007e7f679fcSJeremy L Thompson     CeedCall(CeedElemRestrictionCreateBlockedStrided(delegate, num_elem, elem_size, block_size, num_comp, l_size, strides, rstr));
1008e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
10097509a596Sjeremylt   }
10107509a596Sjeremylt 
1011e7f679fcSJeremy L Thompson   CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative");
10126574a04fSJeremy L Thompson   CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1");
1013e7f679fcSJeremy L Thompson   CeedCheck(block_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1");
1014ca94c3ddSJeremy L Thompson   CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component");
1015e7f679fcSJeremy L Thompson   CeedCheck(l_size >= num_elem * elem_size * num_comp, ceed, CEED_ERROR_DIMENSION, "L-vector size must be at least num_elem * elem_size * num_comp");
1016e022e1f8SJeremy L Thompson 
10172b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, rstr));
1018db002c03SJeremy L Thompson   CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed));
1019d1d35e2fSjeremylt   (*rstr)->ref_count  = 1;
1020d1d35e2fSjeremylt   (*rstr)->num_elem   = num_elem;
1021d1d35e2fSjeremylt   (*rstr)->elem_size  = elem_size;
1022d1d35e2fSjeremylt   (*rstr)->num_comp   = num_comp;
1023d1d35e2fSjeremylt   (*rstr)->l_size     = l_size;
102405fa913cSJeremy L Thompson   (*rstr)->e_size     = num_block * block_size * elem_size * num_comp;
1025e7f679fcSJeremy L Thompson   (*rstr)->num_block  = num_block;
1026e7f679fcSJeremy L Thompson   (*rstr)->block_size = block_size;
1027fcbe8c06SSebastian Grimberg   (*rstr)->rstr_type  = CEED_RESTRICTION_STRIDED;
10282b730f8bSJeremy L Thompson   CeedCall(CeedMalloc(3, &(*rstr)->strides));
10292b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < 3; i++) (*rstr)->strides[i] = strides[i];
1030fcbe8c06SSebastian Grimberg   CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, NULL, NULL, NULL, *rstr));
1031e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
10327509a596Sjeremylt }
10337509a596Sjeremylt 
10347509a596Sjeremylt /**
1035ca94c3ddSJeremy L Thompson   @brief Copy the pointer to a `CeedElemRestriction` and set @ref CeedElemRestrictionApply() implementation to use the unsigned version.
1036c17ec2beSJeremy L Thompson 
1037ca94c3ddSJeremy L Thompson   Both pointers should be destroyed with @ref CeedElemRestrictionDestroy().
1038c17ec2beSJeremy L Thompson 
1039ca94c3ddSJeremy L Thompson   @param[in]     rstr          `CeedElemRestriction` to create unsigned reference to
1040ca94c3ddSJeremy L Thompson   @param[in,out] rstr_unsigned Variable to store unsigned `CeedElemRestriction`
1041c17ec2beSJeremy L Thompson 
1042c17ec2beSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1043c17ec2beSJeremy L Thompson 
1044c17ec2beSJeremy L Thompson   @ref User
1045c17ec2beSJeremy L Thompson **/
1046c17ec2beSJeremy L Thompson int CeedElemRestrictionCreateUnsignedCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_unsigned) {
1047c17ec2beSJeremy L Thompson   CeedCall(CeedCalloc(1, rstr_unsigned));
1048c17ec2beSJeremy L Thompson 
1049c17ec2beSJeremy L Thompson   // Copy old rstr
1050c17ec2beSJeremy L Thompson   memcpy(*rstr_unsigned, rstr, sizeof(struct CeedElemRestriction_private));
1051c17ec2beSJeremy L Thompson   (*rstr_unsigned)->ceed = NULL;
1052c17ec2beSJeremy L Thompson   CeedCall(CeedReferenceCopy(rstr->ceed, &(*rstr_unsigned)->ceed));
1053c17ec2beSJeremy L Thompson   (*rstr_unsigned)->ref_count = 1;
1054c17ec2beSJeremy L Thompson   (*rstr_unsigned)->strides   = NULL;
1055c17ec2beSJeremy L Thompson   if (rstr->strides) {
1056c17ec2beSJeremy L Thompson     CeedCall(CeedMalloc(3, &(*rstr_unsigned)->strides));
1057c17ec2beSJeremy L Thompson     for (CeedInt i = 0; i < 3; i++) (*rstr_unsigned)->strides[i] = rstr->strides[i];
1058c17ec2beSJeremy L Thompson   }
10597c1dbaffSSebastian Grimberg   CeedCall(CeedElemRestrictionReferenceCopy(rstr, &(*rstr_unsigned)->rstr_base));
1060c17ec2beSJeremy L Thompson 
1061c17ec2beSJeremy L Thompson   // Override Apply
1062c17ec2beSJeremy L Thompson   (*rstr_unsigned)->Apply = rstr->ApplyUnsigned;
1063c17ec2beSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1064c17ec2beSJeremy L Thompson }
1065c17ec2beSJeremy L Thompson 
1066c17ec2beSJeremy L Thompson /**
1067ca94c3ddSJeremy L Thompson   @brief Copy the pointer to a `CeedElemRestriction` and set @ref CeedElemRestrictionApply() implementation to use the unoriented version.
10687c1dbaffSSebastian Grimberg 
1069ca94c3ddSJeremy L Thompson   Both pointers should be destroyed with @ref CeedElemRestrictionDestroy().
10707c1dbaffSSebastian Grimberg 
1071ca94c3ddSJeremy L Thompson   @param[in]     rstr            `CeedElemRestriction` to create unoriented reference to
1072ca94c3ddSJeremy L Thompson   @param[in,out] rstr_unoriented Variable to store unoriented `CeedElemRestriction`
10737c1dbaffSSebastian Grimberg 
10747c1dbaffSSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
10757c1dbaffSSebastian Grimberg 
10767c1dbaffSSebastian Grimberg   @ref User
10777c1dbaffSSebastian Grimberg **/
10787c1dbaffSSebastian Grimberg int CeedElemRestrictionCreateUnorientedCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_unoriented) {
10797c1dbaffSSebastian Grimberg   CeedCall(CeedCalloc(1, rstr_unoriented));
10807c1dbaffSSebastian Grimberg 
10817c1dbaffSSebastian Grimberg   // Copy old rstr
10827c1dbaffSSebastian Grimberg   memcpy(*rstr_unoriented, rstr, sizeof(struct CeedElemRestriction_private));
10837c1dbaffSSebastian Grimberg   (*rstr_unoriented)->ceed = NULL;
10847c1dbaffSSebastian Grimberg   CeedCall(CeedReferenceCopy(rstr->ceed, &(*rstr_unoriented)->ceed));
10857c1dbaffSSebastian Grimberg   (*rstr_unoriented)->ref_count = 1;
10867c1dbaffSSebastian Grimberg   (*rstr_unoriented)->strides   = NULL;
10877c1dbaffSSebastian Grimberg   if (rstr->strides) {
10887c1dbaffSSebastian Grimberg     CeedCall(CeedMalloc(3, &(*rstr_unoriented)->strides));
10897c1dbaffSSebastian Grimberg     for (CeedInt i = 0; i < 3; i++) (*rstr_unoriented)->strides[i] = rstr->strides[i];
10907c1dbaffSSebastian Grimberg   }
10917c1dbaffSSebastian Grimberg   CeedCall(CeedElemRestrictionReferenceCopy(rstr, &(*rstr_unoriented)->rstr_base));
10927c1dbaffSSebastian Grimberg 
10937c1dbaffSSebastian Grimberg   // Override Apply
10947c1dbaffSSebastian Grimberg   (*rstr_unoriented)->Apply = rstr->ApplyUnoriented;
10957c1dbaffSSebastian Grimberg   return CEED_ERROR_SUCCESS;
10967c1dbaffSSebastian Grimberg }
10977c1dbaffSSebastian Grimberg 
10987c1dbaffSSebastian Grimberg /**
1099ca94c3ddSJeremy L Thompson   @brief Copy the pointer to a `CeedElemRestriction`.
11009fd66db6SSebastian Grimberg 
1101ca94c3ddSJeremy L Thompson   Both pointers should be destroyed with @ref CeedElemRestrictionDestroy().
11029560d06aSjeremylt 
1103ca94c3ddSJeremy L Thompson   Note: If the value of `*rstr_copy` passed into this function is non-`NULL`, then it is assumed that `*rstr_copy` is a pointer to a `CeedElemRestriction`.
1104ca94c3ddSJeremy L Thompson         This `CeedElemRestriction` will be destroyed if `*rstr_copy` is the only reference to this `CeedElemRestriction`.
1105ea61e9acSJeremy L Thompson 
1106ca94c3ddSJeremy L Thompson   @param[in]     rstr      `CeedElemRestriction` to copy reference to
1107ea61e9acSJeremy L Thompson   @param[in,out] rstr_copy Variable to store copied reference
11089560d06aSjeremylt 
11099560d06aSjeremylt   @return An error code: 0 - success, otherwise - failure
11109560d06aSjeremylt 
11119560d06aSjeremylt   @ref User
11129560d06aSjeremylt **/
11132b730f8bSJeremy L Thompson int CeedElemRestrictionReferenceCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_copy) {
1114393ac2cdSJeremy L Thompson   if (rstr != CEED_ELEMRESTRICTION_NONE) CeedCall(CeedElemRestrictionReference(rstr));
11152b730f8bSJeremy L Thompson   CeedCall(CeedElemRestrictionDestroy(rstr_copy));
11169560d06aSjeremylt   *rstr_copy = rstr;
11179560d06aSjeremylt   return CEED_ERROR_SUCCESS;
11189560d06aSjeremylt }
11199560d06aSjeremylt 
11209560d06aSjeremylt /**
1121ca94c3ddSJeremy L Thompson   @brief Create `CeedVector` associated with a `CeedElemRestriction`
1122b11c1e72Sjeremylt 
1123ca94c3ddSJeremy L Thompson   @param[in]  rstr  `CeedElemRestriction`
1124ca94c3ddSJeremy L Thompson   @param[out] l_vec The address of the L-vector to be created, or `NULL`
1125ca94c3ddSJeremy L Thompson   @param[out] e_vec The address of the E-vector to be created, or `NULL`
1126b11c1e72Sjeremylt 
1127b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1128dfdf5a53Sjeremylt 
11297a982d89SJeremy L. Thompson   @ref User
1130b11c1e72Sjeremylt **/
11312b730f8bSJeremy L Thompson int CeedElemRestrictionCreateVector(CeedElemRestriction rstr, CeedVector *l_vec, CeedVector *e_vec) {
1132d2643443SJeremy L Thompson   CeedSize e_size, l_size;
113348acf710SJeremy L Thompson 
1134d1d35e2fSjeremylt   l_size = rstr->l_size;
113548acf710SJeremy L Thompson   if (rstr->rstr_type == CEED_RESTRICTION_POINTS) {
113648acf710SJeremy L Thompson     e_size = rstr->num_points * rstr->num_comp;
113748acf710SJeremy L Thompson   } else {
1138e7f679fcSJeremy L Thompson     e_size = rstr->num_block * rstr->block_size * rstr->elem_size * rstr->num_comp;
113948acf710SJeremy L Thompson   }
11402b730f8bSJeremy L Thompson   if (l_vec) CeedCall(CeedVectorCreate(rstr->ceed, l_size, l_vec));
11412b730f8bSJeremy L Thompson   if (e_vec) CeedCall(CeedVectorCreate(rstr->ceed, e_size, e_vec));
1142e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1143d7b241e6Sjeremylt }
1144d7b241e6Sjeremylt 
1145d7b241e6Sjeremylt /**
1146d9e1f99aSValeria Barra   @brief Restrict an L-vector to an E-vector or apply its transpose
1147d7b241e6Sjeremylt 
1148ca94c3ddSJeremy L Thompson   @param[in]  rstr    `CeedElemRestriction`
1149ea61e9acSJeremy L Thompson   @param[in]  t_mode  Apply restriction or transpose
1150ca94c3ddSJeremy L Thompson   @param[in]  u       Input vector (of size `l_size` when `t_mode` = @ref CEED_NOTRANSPOSE)
1151ca94c3ddSJeremy L Thompson   @param[out] ru      Output vector (of shape `[num_elem * elem_size]` when `t_mode` = @ref CEED_NOTRANSPOSE).
1152fcbe8c06SSebastian Grimberg                         Ordering of the e-vector is decided by the backend.
1153ea61e9acSJeremy L Thompson   @param[in]  request Request or @ref CEED_REQUEST_IMMEDIATE
1154b11c1e72Sjeremylt 
1155b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1156dfdf5a53Sjeremylt 
11577a982d89SJeremy L. Thompson   @ref User
1158b11c1e72Sjeremylt **/
11592b730f8bSJeremy L Thompson int CeedElemRestrictionApply(CeedElemRestriction rstr, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, CeedRequest *request) {
1160d7b241e6Sjeremylt   CeedInt m, n;
1161d7b241e6Sjeremylt 
1162d1d35e2fSjeremylt   if (t_mode == CEED_NOTRANSPOSE) {
116305fa913cSJeremy L Thompson     m = rstr->e_size;
1164d1d35e2fSjeremylt     n = rstr->l_size;
1165d7b241e6Sjeremylt   } else {
1166d1d35e2fSjeremylt     m = rstr->l_size;
116705fa913cSJeremy L Thompson     n = rstr->e_size;
1168d7b241e6Sjeremylt   }
116905fa913cSJeremy L Thompson   CeedCheck(n <= u->length, rstr->ceed, CEED_ERROR_DIMENSION,
11706574a04fSJeremy L Thompson             "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", u->length, m, n);
117105fa913cSJeremy L Thompson   CeedCheck(m <= ru->length, rstr->ceed, CEED_ERROR_DIMENSION,
11726574a04fSJeremy L Thompson             "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", ru->length, m, n);
11732b730f8bSJeremy L Thompson   if (rstr->num_elem > 0) CeedCall(rstr->Apply(rstr, t_mode, u, ru, request));
1174e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1175d7b241e6Sjeremylt }
1176d7b241e6Sjeremylt 
1177d7b241e6Sjeremylt /**
11783ac8f562SJeremy L Thompson   @brief Restrict an L-vector of points to a single element or apply its transpose
11793ac8f562SJeremy L Thompson 
1180ca94c3ddSJeremy L Thompson   @param[in]  rstr    `CeedElemRestriction`
1181ca94c3ddSJeremy L Thompson   @param[in]  elem    Element number in range `[0, num_elem)`
11823ac8f562SJeremy L Thompson   @param[in]  t_mode  Apply restriction or transpose
1183ca94c3ddSJeremy L Thompson   @param[in]  u       Input vector (of size `l_size` when `t_mode` = @ref CEED_NOTRANSPOSE)
1184ca94c3ddSJeremy L Thompson   @param[out] ru      Output vector (of shape [`num_points * num_comp]` when `t_mode` = @ref CEED_NOTRANSPOSE).
11853ac8f562SJeremy L Thompson                         Ordering of the e-vector is decided by the backend.
11863ac8f562SJeremy L Thompson   @param[in]  request Request or @ref CEED_REQUEST_IMMEDIATE
11873ac8f562SJeremy L Thompson 
11883ac8f562SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
11893ac8f562SJeremy L Thompson 
11903ac8f562SJeremy L Thompson   @ref User
11913ac8f562SJeremy L Thompson **/
119205fa913cSJeremy L Thompson int CeedElemRestrictionApplyAtPointsInElement(CeedElemRestriction rstr, CeedInt elem, CeedTransposeMode t_mode, CeedVector u, CeedVector ru,
11933ac8f562SJeremy L Thompson                                               CeedRequest *request) {
11943ac8f562SJeremy L Thompson   CeedInt m, n;
11953ac8f562SJeremy L Thompson 
11963ac8f562SJeremy L Thompson   if (t_mode == CEED_NOTRANSPOSE) {
11973ac8f562SJeremy L Thompson     CeedCall(CeedElemRestrictionGetNumPointsInElement(rstr, elem, &m));
11983ac8f562SJeremy L Thompson     n = rstr->l_size;
11993ac8f562SJeremy L Thompson   } else {
12003ac8f562SJeremy L Thompson     m = rstr->l_size;
12013ac8f562SJeremy L Thompson     CeedCall(CeedElemRestrictionGetNumPointsInElement(rstr, elem, &n));
12023ac8f562SJeremy L Thompson   }
12033ac8f562SJeremy L Thompson   CeedCheck(n <= u->length, rstr->ceed, CEED_ERROR_DIMENSION,
12043ac8f562SJeremy L Thompson             "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT
12053ac8f562SJeremy L Thompson             ") for element %" CeedInt_FMT,
12063ac8f562SJeremy L Thompson             u->length, m, n, elem);
12073ac8f562SJeremy L Thompson   CeedCheck(m <= ru->length, rstr->ceed, CEED_ERROR_DIMENSION,
12083ac8f562SJeremy L Thompson             "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT
12093ac8f562SJeremy L Thompson             ") for element %" CeedInt_FMT,
12103ac8f562SJeremy L Thompson             ru->length, m, n, elem);
12110930e4e7SJeremy L Thompson   CeedCheck(elem < rstr->num_elem, rstr->ceed, CEED_ERROR_DIMENSION,
12123ac8f562SJeremy L Thompson             "Cannot retrieve element %" CeedInt_FMT ", element %" CeedInt_FMT " > total elements %" CeedInt_FMT "", elem, elem, rstr->num_elem);
121305fa913cSJeremy L Thompson   if (rstr->num_elem > 0) CeedCall(rstr->ApplyAtPointsInElement(rstr, elem, t_mode, u, ru, request));
12143ac8f562SJeremy L Thompson   return CEED_ERROR_SUCCESS;
12153ac8f562SJeremy L Thompson }
12163ac8f562SJeremy L Thompson 
12173ac8f562SJeremy L Thompson /**
1218d9e1f99aSValeria Barra   @brief Restrict an L-vector to a block of an E-vector or apply its transpose
1219be9261b7Sjeremylt 
1220ca94c3ddSJeremy L Thompson   @param[in]  rstr    `CeedElemRestriction`
1221ca94c3ddSJeremy L Thompson   @param[in]  block   Block number to restrict to/from, i.e. `block = 0` will handle elements `[0 : block_size]` and `block = 3` will handle elements `[3*block_size : 4*block_size]`
1222ea61e9acSJeremy L Thompson   @param[in]  t_mode  Apply restriction or transpose
1223ca94c3ddSJeremy L Thompson   @param[in]  u       Input vector (of size `l_size` when `t_mode` = @ref CEED_NOTRANSPOSE)
1224ca94c3ddSJeremy L Thompson   @param[out] ru      Output vector (of shape `[block_size * elem_size]` when `t_mode` = @ref CEED_NOTRANSPOSE).
1225fcbe8c06SSebastian Grimberg                         Ordering of the e-vector is decided by the backend.
1226ea61e9acSJeremy L Thompson   @param[in]  request Request or @ref CEED_REQUEST_IMMEDIATE
1227be9261b7Sjeremylt 
1228be9261b7Sjeremylt   @return An error code: 0 - success, otherwise - failure
1229be9261b7Sjeremylt 
12307a982d89SJeremy L. Thompson   @ref Backend
1231be9261b7Sjeremylt **/
12322b730f8bSJeremy L Thompson int CeedElemRestrictionApplyBlock(CeedElemRestriction rstr, CeedInt block, CeedTransposeMode t_mode, CeedVector u, CeedVector ru,
12332b730f8bSJeremy L Thompson                                   CeedRequest *request) {
1234be9261b7Sjeremylt   CeedInt m, n;
1235be9261b7Sjeremylt 
1236ca94c3ddSJeremy L Thompson   CeedCheck(rstr->ApplyBlock, rstr->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionApplyBlock");
12376402da51SJeremy L Thompson 
1238d1d35e2fSjeremylt   if (t_mode == CEED_NOTRANSPOSE) {
1239e7f679fcSJeremy L Thompson     m = rstr->block_size * rstr->elem_size * rstr->num_comp;
1240d1d35e2fSjeremylt     n = rstr->l_size;
1241be9261b7Sjeremylt   } else {
1242d1d35e2fSjeremylt     m = rstr->l_size;
1243e7f679fcSJeremy L Thompson     n = rstr->block_size * rstr->elem_size * rstr->num_comp;
1244be9261b7Sjeremylt   }
12456574a04fSJeremy L Thompson   CeedCheck(n == u->length, rstr->ceed, CEED_ERROR_DIMENSION,
12466574a04fSJeremy L Thompson             "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", u->length, m, n);
12476574a04fSJeremy L Thompson   CeedCheck(m == ru->length, rstr->ceed, CEED_ERROR_DIMENSION,
12486574a04fSJeremy L Thompson             "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", ru->length, m, n);
1249e7f679fcSJeremy L Thompson   CeedCheck(rstr->block_size * block <= rstr->num_elem, rstr->ceed, CEED_ERROR_DIMENSION,
1250e7f679fcSJeremy L Thompson             "Cannot retrieve block %" CeedInt_FMT ", element %" CeedInt_FMT " > total elements %" CeedInt_FMT "", block, rstr->block_size * block,
12516574a04fSJeremy L Thompson             rstr->num_elem);
12522b730f8bSJeremy L Thompson   CeedCall(rstr->ApplyBlock(rstr, block, t_mode, u, ru, request));
1253e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1254be9261b7Sjeremylt }
1255be9261b7Sjeremylt 
1256be9261b7Sjeremylt /**
1257ca94c3ddSJeremy L Thompson   @brief Get the `Ceed` associated with a `CeedElemRestriction`
1258b7c9bbdaSJeremy L Thompson 
1259ca94c3ddSJeremy L Thompson   @param[in]  rstr `CeedElemRestriction`
1260ca94c3ddSJeremy L Thompson   @param[out] ceed Variable to store `Ceed`
1261b7c9bbdaSJeremy L Thompson 
1262b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1263b7c9bbdaSJeremy L Thompson 
1264b7c9bbdaSJeremy L Thompson   @ref Advanced
1265b7c9bbdaSJeremy L Thompson **/
1266b7c9bbdaSJeremy L Thompson int CeedElemRestrictionGetCeed(CeedElemRestriction rstr, Ceed *ceed) {
1267b7c9bbdaSJeremy L Thompson   *ceed = rstr->ceed;
1268b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1269b7c9bbdaSJeremy L Thompson }
1270b7c9bbdaSJeremy L Thompson 
1271b7c9bbdaSJeremy L Thompson /**
1272d979a051Sjeremylt   @brief Get the L-vector component stride
1273a681ae63Sjeremylt 
1274ca94c3ddSJeremy L Thompson   @param[in]  rstr        `CeedElemRestriction`
1275d1d35e2fSjeremylt   @param[out] comp_stride Variable to store component stride
1276a681ae63Sjeremylt 
1277a681ae63Sjeremylt   @return An error code: 0 - success, otherwise - failure
1278a681ae63Sjeremylt 
1279b7c9bbdaSJeremy L Thompson   @ref Advanced
1280a681ae63Sjeremylt **/
12812b730f8bSJeremy L Thompson int CeedElemRestrictionGetCompStride(CeedElemRestriction rstr, CeedInt *comp_stride) {
1282d1d35e2fSjeremylt   *comp_stride = rstr->comp_stride;
1283e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1284a681ae63Sjeremylt }
1285a681ae63Sjeremylt 
1286a681ae63Sjeremylt /**
1287ca94c3ddSJeremy L Thompson   @brief Get the total number of elements in the range of a `CeedElemRestriction`
1288a681ae63Sjeremylt 
1289ca94c3ddSJeremy L Thompson   @param[in] rstr      `CeedElemRestriction`
1290d1d35e2fSjeremylt   @param[out] num_elem Variable to store number of elements
1291a681ae63Sjeremylt 
1292a681ae63Sjeremylt   @return An error code: 0 - success, otherwise - failure
1293a681ae63Sjeremylt 
1294b7c9bbdaSJeremy L Thompson   @ref Advanced
1295a681ae63Sjeremylt **/
12962b730f8bSJeremy L Thompson int CeedElemRestrictionGetNumElements(CeedElemRestriction rstr, CeedInt *num_elem) {
1297d1d35e2fSjeremylt   *num_elem = rstr->num_elem;
1298e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1299a681ae63Sjeremylt }
1300a681ae63Sjeremylt 
1301a681ae63Sjeremylt /**
1302ca94c3ddSJeremy L Thompson   @brief Get the size of elements in the `CeedElemRestriction`
1303a681ae63Sjeremylt 
1304ca94c3ddSJeremy L Thompson   @param[in]  rstr      `CeedElemRestriction`
1305d1d35e2fSjeremylt   @param[out] elem_size Variable to store size of elements
1306a681ae63Sjeremylt 
1307a681ae63Sjeremylt   @return An error code: 0 - success, otherwise - failure
1308a681ae63Sjeremylt 
1309b7c9bbdaSJeremy L Thompson   @ref Advanced
1310a681ae63Sjeremylt **/
13112b730f8bSJeremy L Thompson int CeedElemRestrictionGetElementSize(CeedElemRestriction rstr, CeedInt *elem_size) {
1312d1d35e2fSjeremylt   *elem_size = rstr->elem_size;
13132c7e7413SJeremy L Thompson   return CEED_ERROR_SUCCESS;
13142c7e7413SJeremy L Thompson }
13152c7e7413SJeremy L Thompson 
13162c7e7413SJeremy L Thompson /**
131707d5dec1SJeremy L Thompson 
1318ca94c3ddSJeremy L Thompson   @brief Get the number of points in the l-vector for a points `CeedElemRestriction`
131907d5dec1SJeremy L Thompson 
1320ca94c3ddSJeremy L Thompson   @param[in]  rstr       `CeedElemRestriction`
132107d5dec1SJeremy L Thompson   @param[out] num_points The number of points in the l-vector
132207d5dec1SJeremy L Thompson 
132307d5dec1SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
132407d5dec1SJeremy L Thompson 
1325c63574e3SJeremy L Thompson   @ref User
132607d5dec1SJeremy L Thompson **/
132707d5dec1SJeremy L Thompson int CeedElemRestrictionGetNumPoints(CeedElemRestriction rstr, CeedInt *num_points) {
132807d5dec1SJeremy L Thompson   Ceed ceed;
132907d5dec1SJeremy L Thompson 
133007d5dec1SJeremy L Thompson   CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed));
133107d5dec1SJeremy L Thompson   CeedCheck(rstr->rstr_type == CEED_RESTRICTION_POINTS, ceed, CEED_ERROR_INCOMPATIBLE,
133207d5dec1SJeremy L Thompson             "Can only retrieve the number of points for a points CeedElemRestriction");
133307d5dec1SJeremy L Thompson 
133407d5dec1SJeremy L Thompson   *num_points = rstr->num_points;
133507d5dec1SJeremy L Thompson   return CEED_ERROR_SUCCESS;
133607d5dec1SJeremy L Thompson }
133707d5dec1SJeremy L Thompson 
133807d5dec1SJeremy L Thompson /**
133907d5dec1SJeremy L Thompson 
1340ca94c3ddSJeremy L Thompson   @brief Get the number of points in an element of a `CeedElemRestriction` at points
134107d5dec1SJeremy L Thompson 
1342ca94c3ddSJeremy L Thompson   @param[in]  rstr       `CeedElemRestriction`
134307d5dec1SJeremy L Thompson   @param[in]  elem       Index number of element to retrieve the number of points for
134407d5dec1SJeremy L Thompson   @param[out] num_points The number of points in the element at index elem
134507d5dec1SJeremy L Thompson 
134607d5dec1SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
134707d5dec1SJeremy L Thompson 
1348c63574e3SJeremy L Thompson   @ref User
134907d5dec1SJeremy L Thompson **/
135007d5dec1SJeremy L Thompson int CeedElemRestrictionGetNumPointsInElement(CeedElemRestriction rstr, CeedInt elem, CeedInt *num_points) {
135107d5dec1SJeremy L Thompson   Ceed           ceed;
135207d5dec1SJeremy L Thompson   const CeedInt *offsets;
135307d5dec1SJeremy L Thompson 
135407d5dec1SJeremy L Thompson   CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed));
135507d5dec1SJeremy L Thompson   CeedCheck(rstr->rstr_type == CEED_RESTRICTION_POINTS, ceed, CEED_ERROR_INCOMPATIBLE,
135607d5dec1SJeremy L Thompson             "Can only retrieve the number of points for a points CeedElemRestriction");
135707d5dec1SJeremy L Thompson 
135807d5dec1SJeremy L Thompson   CeedCall(CeedElemRestrictionGetOffsets(rstr, CEED_MEM_HOST, &offsets));
135907d5dec1SJeremy L Thompson   *num_points = offsets[elem + 1] - offsets[elem];
136007d5dec1SJeremy L Thompson   CeedCall(CeedElemRestrictionRestoreOffsets(rstr, &offsets));
136107d5dec1SJeremy L Thompson   return CEED_ERROR_SUCCESS;
136207d5dec1SJeremy L Thompson }
136307d5dec1SJeremy L Thompson 
136407d5dec1SJeremy L Thompson /**
1365ca94c3ddSJeremy L Thompson   @brief Get the maximum number of points in an element for a `CeedElemRestriction` at points
13662c7e7413SJeremy L Thompson 
1367ca94c3ddSJeremy L Thompson   @param[in]  rstr       `CeedElemRestriction`
13682c7e7413SJeremy L Thompson   @param[out] max_points Variable to store size of elements
13692c7e7413SJeremy L Thompson 
13702c7e7413SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
13712c7e7413SJeremy L Thompson 
13722c7e7413SJeremy L Thompson   @ref Advanced
13732c7e7413SJeremy L Thompson **/
13742c7e7413SJeremy L Thompson int CeedElemRestrictionGetMaxPointsInElement(CeedElemRestriction rstr, CeedInt *max_points) {
13752c7e7413SJeremy L Thompson   Ceed                ceed;
13762c7e7413SJeremy L Thompson   CeedInt             num_elem;
13772c7e7413SJeremy L Thompson   CeedRestrictionType rstr_type;
13782c7e7413SJeremy L Thompson 
13792c7e7413SJeremy L Thompson   CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed));
13802c7e7413SJeremy L Thompson   CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type));
13812c7e7413SJeremy L Thompson   CeedCheck(rstr_type == CEED_RESTRICTION_POINTS, ceed, CEED_ERROR_INCOMPATIBLE,
13822c7e7413SJeremy L Thompson             "Cannot compute max points for a CeedElemRestriction that does not use points");
13832c7e7413SJeremy L Thompson 
13842c7e7413SJeremy L Thompson   CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem));
13852c7e7413SJeremy L Thompson   *max_points = 0;
13862c7e7413SJeremy L Thompson   for (CeedInt e = 0; e < num_elem; e++) {
13872c7e7413SJeremy L Thompson     CeedInt num_points;
13882c7e7413SJeremy L Thompson 
13892c7e7413SJeremy L Thompson     CeedCall(CeedElemRestrictionGetNumPointsInElement(rstr, e, &num_points));
13902c7e7413SJeremy L Thompson     *max_points = CeedIntMax(num_points, *max_points);
13912c7e7413SJeremy L Thompson   }
1392e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1393a681ae63Sjeremylt }
1394a681ae63Sjeremylt 
1395a681ae63Sjeremylt /**
1396ca94c3ddSJeremy L Thompson   @brief Get the size of the l-vector for a `CeedElemRestriction`
1397a681ae63Sjeremylt 
1398ca94c3ddSJeremy L Thompson   @param[in]  rstr   `CeedElemRestriction`
1399d1d35e2fSjeremylt   @param[out] l_size Variable to store number of nodes
1400a681ae63Sjeremylt 
1401a681ae63Sjeremylt   @return An error code: 0 - success, otherwise - failure
1402a681ae63Sjeremylt 
1403b7c9bbdaSJeremy L Thompson   @ref Advanced
1404a681ae63Sjeremylt **/
14052b730f8bSJeremy L Thompson int CeedElemRestrictionGetLVectorSize(CeedElemRestriction rstr, CeedSize *l_size) {
1406d1d35e2fSjeremylt   *l_size = rstr->l_size;
1407e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1408a681ae63Sjeremylt }
1409a681ae63Sjeremylt 
1410a681ae63Sjeremylt /**
1411ca94c3ddSJeremy L Thompson   @brief Get the number of components in the elements of a `CeedElemRestriction`
1412a681ae63Sjeremylt 
1413ca94c3ddSJeremy L Thompson   @param[in]  rstr     `CeedElemRestriction`
1414d1d35e2fSjeremylt   @param[out] num_comp Variable to store number of components
1415a681ae63Sjeremylt 
1416a681ae63Sjeremylt   @return An error code: 0 - success, otherwise - failure
1417a681ae63Sjeremylt 
1418b7c9bbdaSJeremy L Thompson   @ref Advanced
1419a681ae63Sjeremylt **/
14202b730f8bSJeremy L Thompson int CeedElemRestrictionGetNumComponents(CeedElemRestriction rstr, CeedInt *num_comp) {
1421d1d35e2fSjeremylt   *num_comp = rstr->num_comp;
1422e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1423a681ae63Sjeremylt }
1424a681ae63Sjeremylt 
1425a681ae63Sjeremylt /**
1426ca94c3ddSJeremy L Thompson   @brief Get the number of blocks in a `CeedElemRestriction`
1427a681ae63Sjeremylt 
1428ca94c3ddSJeremy L Thompson   @param[in]  rstr      `CeedElemRestriction`
1429d1d35e2fSjeremylt   @param[out] num_block Variable to store number of blocks
1430a681ae63Sjeremylt 
1431a681ae63Sjeremylt   @return An error code: 0 - success, otherwise - failure
1432a681ae63Sjeremylt 
1433b7c9bbdaSJeremy L Thompson   @ref Advanced
1434a681ae63Sjeremylt **/
14352b730f8bSJeremy L Thompson int CeedElemRestrictionGetNumBlocks(CeedElemRestriction rstr, CeedInt *num_block) {
1436e7f679fcSJeremy L Thompson   *num_block = rstr->num_block;
1437e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1438a681ae63Sjeremylt }
1439a681ae63Sjeremylt 
1440a681ae63Sjeremylt /**
1441ca94c3ddSJeremy L Thompson   @brief Get the size of blocks in the `CeedElemRestriction`
1442a681ae63Sjeremylt 
1443ca94c3ddSJeremy L Thompson   @param[in]  rstr       `CeedElemRestriction`
1444e7f679fcSJeremy L Thompson   @param[out] block_size Variable to store size of blocks
1445a681ae63Sjeremylt 
1446a681ae63Sjeremylt   @return An error code: 0 - success, otherwise - failure
1447a681ae63Sjeremylt 
1448b7c9bbdaSJeremy L Thompson   @ref Advanced
1449a681ae63Sjeremylt **/
1450e7f679fcSJeremy L Thompson int CeedElemRestrictionGetBlockSize(CeedElemRestriction rstr, CeedInt *block_size) {
1451e7f679fcSJeremy L Thompson   *block_size = rstr->block_size;
1452e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1453a681ae63Sjeremylt }
1454a681ae63Sjeremylt 
1455a681ae63Sjeremylt /**
1456ca94c3ddSJeremy L Thompson   @brief Get the multiplicity of nodes in a `CeedElemRestriction`
14571469ee4dSjeremylt 
1458ca94c3ddSJeremy L Thompson   @param[in]  rstr `CeedElemRestriction`
1459ca94c3ddSJeremy L Thompson   @param[out] mult Vector to store multiplicity (of size `l_size`)
14601469ee4dSjeremylt 
14611469ee4dSjeremylt   @return An error code: 0 - success, otherwise - failure
14621469ee4dSjeremylt 
14637a982d89SJeremy L. Thompson   @ref User
14641469ee4dSjeremylt **/
14652b730f8bSJeremy L Thompson int CeedElemRestrictionGetMultiplicity(CeedElemRestriction rstr, CeedVector mult) {
1466d1d35e2fSjeremylt   CeedVector e_vec;
14671469ee4dSjeremylt 
146825509ebbSRezgar Shakeri   // Create e_vec to hold intermediate computation in E^T (E 1)
14692b730f8bSJeremy L Thompson   CeedCall(CeedElemRestrictionCreateVector(rstr, NULL, &e_vec));
14701469ee4dSjeremylt 
147125509ebbSRezgar Shakeri   // Compute e_vec = E * 1
14722b730f8bSJeremy L Thompson   CeedCall(CeedVectorSetValue(mult, 1.0));
14732b730f8bSJeremy L Thompson   CeedCall(CeedElemRestrictionApply(rstr, CEED_NOTRANSPOSE, mult, e_vec, CEED_REQUEST_IMMEDIATE));
147425509ebbSRezgar Shakeri   // Compute multiplicity, mult = E^T * e_vec = E^T (E 1)
14752b730f8bSJeremy L Thompson   CeedCall(CeedVectorSetValue(mult, 0.0));
14762b730f8bSJeremy L Thompson   CeedCall(CeedElemRestrictionApply(rstr, CEED_TRANSPOSE, e_vec, mult, CEED_REQUEST_IMMEDIATE));
14771469ee4dSjeremylt   // Cleanup
14782b730f8bSJeremy L Thompson   CeedCall(CeedVectorDestroy(&e_vec));
1479e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
14801469ee4dSjeremylt }
14811469ee4dSjeremylt 
14821469ee4dSjeremylt /**
1483ca94c3ddSJeremy L Thompson   @brief View a `CeedElemRestriction`
1484f02ca4a2SJed Brown 
1485ca94c3ddSJeremy L Thompson   @param[in] rstr   `CeedElemRestriction` to view
1486ca94c3ddSJeremy L Thompson   @param[in] stream Stream to write; typically `stdout` or a file
1487f02ca4a2SJed Brown 
1488f02ca4a2SJed Brown   @return Error code: 0 - success, otherwise - failure
1489f02ca4a2SJed Brown 
14907a982d89SJeremy L. Thompson   @ref User
1491f02ca4a2SJed Brown **/
1492f02ca4a2SJed Brown int CeedElemRestrictionView(CeedElemRestriction rstr, FILE *stream) {
14930930e4e7SJeremy L Thompson   CeedRestrictionType rstr_type;
14940930e4e7SJeremy L Thompson 
14950930e4e7SJeremy L Thompson   CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type));
14960930e4e7SJeremy L Thompson 
14970930e4e7SJeremy L Thompson   if (rstr_type == CEED_RESTRICTION_POINTS) {
14980930e4e7SJeremy L Thompson     CeedInt max_points;
14990930e4e7SJeremy L Thompson 
15000930e4e7SJeremy L Thompson     CeedCall(CeedElemRestrictionGetMaxPointsInElement(rstr, &max_points));
15010930e4e7SJeremy L Thompson     fprintf(stream,
15020930e4e7SJeremy L Thompson             "CeedElemRestriction at points from (%td, %" CeedInt_FMT ") to %" CeedInt_FMT " elements with a maximum of %" CeedInt_FMT
15030930e4e7SJeremy L Thompson             " points on an element\n",
15040930e4e7SJeremy L Thompson             rstr->l_size, rstr->num_comp, rstr->num_elem, max_points);
15050930e4e7SJeremy L Thompson   } else {
15067509a596Sjeremylt     char stridesstr[500];
15071c66c397SJeremy L Thompson 
15082b730f8bSJeremy L Thompson     if (rstr->strides) {
15092b730f8bSJeremy L Thompson       sprintf(stridesstr, "[%" CeedInt_FMT ", %" CeedInt_FMT ", %" CeedInt_FMT "]", rstr->strides[0], rstr->strides[1], rstr->strides[2]);
15102b730f8bSJeremy L Thompson     } else {
1511990fdeb6SJeremy L Thompson       sprintf(stridesstr, "%" CeedInt_FMT, rstr->comp_stride);
15122b730f8bSJeremy L Thompson     }
15132b730f8bSJeremy L Thompson     fprintf(stream, "%sCeedElemRestriction from (%td, %" CeedInt_FMT ") to %" CeedInt_FMT " elements with %" CeedInt_FMT " nodes each and %s %s\n",
1514e7f679fcSJeremy L Thompson             rstr->block_size > 1 ? "Blocked " : "", rstr->l_size, rstr->num_comp, rstr->num_elem, rstr->elem_size,
1515d979a051Sjeremylt             rstr->strides ? "strides" : "component stride", stridesstr);
15160930e4e7SJeremy L Thompson   }
1517e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1518f02ca4a2SJed Brown }
1519f02ca4a2SJed Brown 
1520f02ca4a2SJed Brown /**
1521ca94c3ddSJeremy L Thompson   @brief Destroy a `CeedElemRestriction`
1522b11c1e72Sjeremylt 
1523ca94c3ddSJeremy L Thompson   @param[in,out] rstr `CeedElemRestriction` to destroy
1524b11c1e72Sjeremylt 
1525b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1526dfdf5a53Sjeremylt 
15277a982d89SJeremy L. Thompson   @ref User
1528b11c1e72Sjeremylt **/
15294ce2993fSjeremylt int CeedElemRestrictionDestroy(CeedElemRestriction *rstr) {
1530393ac2cdSJeremy L Thompson   if (!*rstr || *rstr == CEED_ELEMRESTRICTION_NONE || --(*rstr)->ref_count > 0) {
1531ad6481ceSJeremy L Thompson     *rstr = NULL;
1532ad6481ceSJeremy L Thompson     return CEED_ERROR_SUCCESS;
1533ad6481ceSJeremy L Thompson   }
15346574a04fSJeremy L Thompson   CeedCheck((*rstr)->num_readers == 0, (*rstr)->ceed, CEED_ERROR_ACCESS,
15356574a04fSJeremy L Thompson             "Cannot destroy CeedElemRestriction, a process has read access to the offset data");
1536c17ec2beSJeremy L Thompson 
1537c17ec2beSJeremy L Thompson   // Only destroy backend data once between rstr and unsigned copy
15387c1dbaffSSebastian Grimberg   if ((*rstr)->rstr_base) CeedCall(CeedElemRestrictionDestroy(&(*rstr)->rstr_base));
1539c17ec2beSJeremy L Thompson   else if ((*rstr)->Destroy) CeedCall((*rstr)->Destroy(*rstr));
1540c17ec2beSJeremy L Thompson 
15412b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*rstr)->strides));
15422b730f8bSJeremy L Thompson   CeedCall(CeedDestroy(&(*rstr)->ceed));
15432b730f8bSJeremy L Thompson   CeedCall(CeedFree(rstr));
1544e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1545d7b241e6Sjeremylt }
1546d7b241e6Sjeremylt 
1547d7b241e6Sjeremylt /// @}
1548