xref: /libCEED/interface/ceed-elemrestriction.c (revision 77d1c127eaba12da4c1761ef74a16ca3fc16e493)
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 /**
25d979a051Sjeremylt   @brief Permute and pad offsets for a blocked restriction
267a982d89SJeremy L. Thompson 
27*77d1c127SSebastian Grimberg   @param[in]  offsets     Array of shape [@a num_elem, @a elem_size]. Row i holds the ordered list of the offsets (into the input CeedVector) for the
28*77d1c127SSebastian Grimberg unknowns corresponding to element i, where 0 <= i < @a num_elem. All offsets must be in the range [0, @a l_size - 1].
29ea61e9acSJeremy L Thompson   @param[out] blk_offsets Array of permuted and padded offsets of shape [@a num_blk, @a elem_size, @a blk_size].
30ea61e9acSJeremy L Thompson   @param[in]  num_blk     Number of blocks
31ea61e9acSJeremy L Thompson   @param[in]  num_elem    Number of elements
32ea61e9acSJeremy L Thompson   @param[in]  blk_size    Number of elements in a block
33ea61e9acSJeremy L Thompson   @param[in]  elem_size   Size of each element
347a982d89SJeremy L. Thompson 
357a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
367a982d89SJeremy L. Thompson 
377a982d89SJeremy L. Thompson   @ref Utility
387a982d89SJeremy L. Thompson **/
392b730f8bSJeremy L Thompson int CeedPermutePadOffsets(const CeedInt *offsets, CeedInt *blk_offsets, CeedInt num_blk, CeedInt num_elem, CeedInt blk_size, CeedInt elem_size) {
402b730f8bSJeremy L Thompson   for (CeedInt e = 0; e < num_blk * blk_size; e += blk_size) {
412b730f8bSJeremy L Thompson     for (CeedInt j = 0; j < blk_size; j++) {
422b730f8bSJeremy L Thompson       for (CeedInt k = 0; k < elem_size; k++) {
432b730f8bSJeremy L Thompson         blk_offsets[e * elem_size + k * blk_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 
50*77d1c127SSebastian Grimberg /**
51*77d1c127SSebastian Grimberg   @brief Permute and pad orientations for a blocked restriction
52*77d1c127SSebastian Grimberg 
53*77d1c127SSebastian Grimberg   @param[in]  orients     Array of shape [@a num_elem, @a elem_size]. Row i holds the ordered list of the orientations (into the input CeedVector) for
54*77d1c127SSebastian Grimberg the unknowns corresponding to element i, where 0 <= i < @a num_elem.
55*77d1c127SSebastian Grimberg   @param[out] blk_orients Array of permuted and padded orientations of shape [@a num_blk, @a elem_size, @a blk_size].
56*77d1c127SSebastian Grimberg   @param[in]  num_blk     Number of blocks
57*77d1c127SSebastian Grimberg   @param[in]  num_elem    Number of elements
58*77d1c127SSebastian Grimberg   @param[in]  blk_size    Number of elements in a block
59*77d1c127SSebastian Grimberg   @param[in]  elem_size   Size of each element
60*77d1c127SSebastian Grimberg 
61*77d1c127SSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
62*77d1c127SSebastian Grimberg 
63*77d1c127SSebastian Grimberg   @ref Utility
64*77d1c127SSebastian Grimberg **/
65*77d1c127SSebastian Grimberg int CeedPermutePadOrientations(const bool *orients, bool *blk_orients, CeedInt num_blk, CeedInt num_elem, CeedInt blk_size, CeedInt elem_size) {
66*77d1c127SSebastian Grimberg   for (CeedInt e = 0; e < num_blk * blk_size; e += blk_size) {
67*77d1c127SSebastian Grimberg     for (CeedInt j = 0; j < blk_size; j++) {
68*77d1c127SSebastian Grimberg       for (CeedInt k = 0; k < elem_size; k++) {
69*77d1c127SSebastian Grimberg         blk_orients[e * elem_size + k * blk_size + j] = orients[CeedIntMin(e + j, num_elem - 1) * elem_size + k];
70*77d1c127SSebastian Grimberg       }
71*77d1c127SSebastian Grimberg     }
72*77d1c127SSebastian Grimberg   }
73*77d1c127SSebastian Grimberg   return CEED_ERROR_SUCCESS;
74*77d1c127SSebastian Grimberg }
75*77d1c127SSebastian Grimberg 
767a982d89SJeremy L. Thompson /// @}
777a982d89SJeremy L. Thompson 
787a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
797a982d89SJeremy L. Thompson /// CeedElemRestriction Backend API
807a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
817a982d89SJeremy L. Thompson /// @addtogroup CeedElemRestrictionBackend
827a982d89SJeremy L. Thompson /// @{
837a982d89SJeremy L. Thompson 
847a982d89SJeremy L. Thompson /**
8578b2e752SJeremy L Thompson   @brief Restrict an L-vector to an E-vector or apply its transpose ignoring any
8678b2e752SJeremy L Thompson          provided orientations
8778b2e752SJeremy L Thompson 
8878b2e752SJeremy L Thompson   @param[in]  rstr    CeedElemRestriction
8978b2e752SJeremy L Thompson   @param[in]  t_mode  Apply restriction or transpose
9078b2e752SJeremy L Thompson   @param[in]  u       Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE)
9178b2e752SJeremy L Thompson   @param[out] ru      Output vector (of shape [@a num_elem * @a elem_size] when t_mode=@ref CEED_NOTRANSPOSE).
9278b2e752SJeremy L Thompson                         Ordering of the e-vector is decided by the backend.
9378b2e752SJeremy L Thompson   @param[in]  request Request or @ref CEED_REQUEST_IMMEDIATE
9478b2e752SJeremy L Thompson 
9578b2e752SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
9678b2e752SJeremy L Thompson 
9778b2e752SJeremy L Thompson   @ref User
9878b2e752SJeremy L Thompson **/
9978b2e752SJeremy L Thompson int CeedElemRestrictionApplyUnsigned(CeedElemRestriction rstr, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, CeedRequest *request) {
10078b2e752SJeremy L Thompson   CeedInt m, n;
10178b2e752SJeremy L Thompson 
10278b2e752SJeremy L Thompson   CeedCheck(rstr->ApplyUnsigned, rstr->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support ElemRestrictionApplyUnsigned");
10378b2e752SJeremy L Thompson 
10478b2e752SJeremy L Thompson   if (t_mode == CEED_NOTRANSPOSE) {
10578b2e752SJeremy L Thompson     m = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp;
10678b2e752SJeremy L Thompson     n = rstr->l_size;
10778b2e752SJeremy L Thompson   } else {
10878b2e752SJeremy L Thompson     m = rstr->l_size;
10978b2e752SJeremy L Thompson     n = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp;
11078b2e752SJeremy L Thompson   }
11178b2e752SJeremy L Thompson   CeedCheck(n == u->length, rstr->ceed, CEED_ERROR_DIMENSION,
11278b2e752SJeremy L Thompson             "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", u->length, m, n);
11378b2e752SJeremy L Thompson   CeedCheck(m == ru->length, rstr->ceed, CEED_ERROR_DIMENSION,
11478b2e752SJeremy L Thompson             "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", ru->length, m, n);
11578b2e752SJeremy L Thompson   if (rstr->num_elem > 0) CeedCall(rstr->ApplyUnsigned(rstr, t_mode, u, ru, request));
116*77d1c127SSebastian Grimberg 
11778b2e752SJeremy L Thompson   return CEED_ERROR_SUCCESS;
11878b2e752SJeremy L Thompson }
11978b2e752SJeremy L Thompson 
12078b2e752SJeremy L Thompson /**
121a681ae63Sjeremylt 
122a681ae63Sjeremylt   @brief Get the strides of a strided CeedElemRestriction
1237a982d89SJeremy L. Thompson 
124ea61e9acSJeremy L Thompson   @param[in]  rstr    CeedElemRestriction
125a681ae63Sjeremylt   @param[out] strides Variable to store strides array
1267a982d89SJeremy L. Thompson 
1277a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1287a982d89SJeremy L. Thompson 
1297a982d89SJeremy L. Thompson   @ref Backend
1307a982d89SJeremy L. Thompson **/
1312b730f8bSJeremy L Thompson int CeedElemRestrictionGetStrides(CeedElemRestriction rstr, CeedInt (*strides)[3]) {
1326574a04fSJeremy L Thompson   CeedCheck(rstr->strides, rstr->ceed, CEED_ERROR_MINOR, "ElemRestriction has no stride data");
1332b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < 3; i++) (*strides)[i] = rstr->strides[i];
134e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1357a982d89SJeremy L. Thompson }
1367a982d89SJeremy L. Thompson 
1377a982d89SJeremy L. Thompson /**
138*77d1c127SSebastian Grimberg   @brief Get the backend stride status of a CeedElemRestriction
139*77d1c127SSebastian Grimberg 
140*77d1c127SSebastian Grimberg   @param[in]  rstr                 CeedElemRestriction
141*77d1c127SSebastian Grimberg   @param[out] has_backend_strides  Variable to store stride status
142*77d1c127SSebastian Grimberg 
143*77d1c127SSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
144*77d1c127SSebastian Grimberg 
145*77d1c127SSebastian Grimberg   @ref Backend
146*77d1c127SSebastian Grimberg **/
147*77d1c127SSebastian Grimberg int CeedElemRestrictionHasBackendStrides(CeedElemRestriction rstr, bool *has_backend_strides) {
148*77d1c127SSebastian Grimberg   CeedCheck(rstr->strides, rstr->ceed, CEED_ERROR_MINOR, "ElemRestriction has no stride data");
149*77d1c127SSebastian Grimberg   *has_backend_strides = ((rstr->strides[0] == CEED_STRIDES_BACKEND[0]) && (rstr->strides[1] == CEED_STRIDES_BACKEND[1]) &&
150*77d1c127SSebastian Grimberg                           (rstr->strides[2] == CEED_STRIDES_BACKEND[2]));
151*77d1c127SSebastian Grimberg   return CEED_ERROR_SUCCESS;
152*77d1c127SSebastian Grimberg }
153*77d1c127SSebastian Grimberg 
154*77d1c127SSebastian Grimberg /**
155bd33150aSjeremylt   @brief Get read-only access to a CeedElemRestriction offsets array by memtype
156bd33150aSjeremylt 
157ea61e9acSJeremy L Thompson   @param[in]  rstr     CeedElemRestriction to retrieve offsets
158*77d1c127SSebastian Grimberg   @param[in]  mem_type Memory type on which to access the array. If the backend uses a different memory type, this will perform a copy (possibly
159*77d1c127SSebastian Grimberg cached).
160d1d35e2fSjeremylt   @param[out] offsets Array on memory type mem_type
161bd33150aSjeremylt 
162bd33150aSjeremylt   @return An error code: 0 - success, otherwise - failure
163bd33150aSjeremylt 
164bd33150aSjeremylt   @ref User
165bd33150aSjeremylt **/
1662b730f8bSJeremy L Thompson int CeedElemRestrictionGetOffsets(CeedElemRestriction rstr, CeedMemType mem_type, const CeedInt **offsets) {
167c17ec2beSJeremy L Thompson   if (rstr->rstr_signed) {
168c17ec2beSJeremy L Thompson     CeedCall(CeedElemRestrictionGetOffsets(rstr->rstr_signed, mem_type, offsets));
169c17ec2beSJeremy L Thompson   } else {
1706574a04fSJeremy L Thompson     CeedCheck(rstr->GetOffsets, rstr->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support GetOffsets");
1712b730f8bSJeremy L Thompson     CeedCall(rstr->GetOffsets(rstr, mem_type, offsets));
172d1d35e2fSjeremylt     rstr->num_readers++;
173c17ec2beSJeremy L Thompson   }
174e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
175430758c8SJeremy L Thompson }
176430758c8SJeremy L Thompson 
177430758c8SJeremy L Thompson /**
178430758c8SJeremy L Thompson   @brief Restore an offsets array obtained using CeedElemRestrictionGetOffsets()
179430758c8SJeremy L Thompson 
180ea61e9acSJeremy L Thompson   @param[in] rstr    CeedElemRestriction to restore
181ea61e9acSJeremy L Thompson   @param[in] offsets Array of offset data
182430758c8SJeremy L Thompson 
183430758c8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
184430758c8SJeremy L Thompson 
185430758c8SJeremy L Thompson   @ref User
186430758c8SJeremy L Thompson **/
1872b730f8bSJeremy L Thompson int CeedElemRestrictionRestoreOffsets(CeedElemRestriction rstr, const CeedInt **offsets) {
188c17ec2beSJeremy L Thompson   if (rstr->rstr_signed) {
189c17ec2beSJeremy L Thompson     CeedCall(CeedElemRestrictionRestoreOffsets(rstr->rstr_signed, offsets));
190c17ec2beSJeremy L Thompson   } else {
191430758c8SJeremy L Thompson     *offsets = NULL;
192d1d35e2fSjeremylt     rstr->num_readers--;
193c17ec2beSJeremy L Thompson   }
194e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
195bd33150aSjeremylt }
196bd33150aSjeremylt 
197bd33150aSjeremylt /**
198*77d1c127SSebastian Grimberg   @brief Get read-only access to a CeedElemRestriction orientations array by memtype
1993ac43b2cSJeremy L Thompson 
200*77d1c127SSebastian Grimberg   @param[in]  rstr     CeedElemRestriction to retrieve orientations
201*77d1c127SSebastian Grimberg   @param[in]  mem_type Memory type on which to access the array. If the backend uses a different memory type, this will perform a copy (possibly
202*77d1c127SSebastian Grimberg cached).
203*77d1c127SSebastian Grimberg   @param[out] orients  Array on memory type mem_type
2043ac43b2cSJeremy L Thompson 
2053ac43b2cSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
2063ac43b2cSJeremy L Thompson 
207*77d1c127SSebastian Grimberg   @ref User
2083ac43b2cSJeremy L Thompson **/
209*77d1c127SSebastian Grimberg int CeedElemRestrictionGetOrientations(CeedElemRestriction rstr, CeedMemType mem_type, const bool **orients) {
210*77d1c127SSebastian Grimberg   CeedCheck(rstr->GetOrientations, rstr->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement GetOrientations");
211*77d1c127SSebastian Grimberg   CeedCall(rstr->GetOrientations(rstr, mem_type, orients));
212*77d1c127SSebastian Grimberg   rstr->num_readers++;
213e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2143ac43b2cSJeremy L Thompson }
2153ac43b2cSJeremy L Thompson 
2163ac43b2cSJeremy L Thompson /**
217*77d1c127SSebastian Grimberg   @brief Restore an orientations array obtained using CeedElemRestrictionGetOrientations()
218b435c5a6Srezgarshakeri 
219*77d1c127SSebastian Grimberg   @param[in] rstr    CeedElemRestriction to restore
220*77d1c127SSebastian Grimberg   @param[in] orients Array of orientation data
221b435c5a6Srezgarshakeri 
222b435c5a6Srezgarshakeri   @return An error code: 0 - success, otherwise - failure
223b435c5a6Srezgarshakeri 
224*77d1c127SSebastian Grimberg   @ref User
225b435c5a6Srezgarshakeri **/
226*77d1c127SSebastian Grimberg int CeedElemRestrictionRestoreOrientations(CeedElemRestriction rstr, const bool **orients) {
227*77d1c127SSebastian Grimberg   *orients = NULL;
228*77d1c127SSebastian Grimberg   rstr->num_readers--;
229b435c5a6Srezgarshakeri   return CEED_ERROR_SUCCESS;
230b435c5a6Srezgarshakeri }
231b435c5a6Srezgarshakeri 
232b435c5a6Srezgarshakeri /**
233*77d1c127SSebastian Grimberg   @brief Get read-only access to a CeedElemRestriction curl-conforming orientations array by memtype
2347a982d89SJeremy L. Thompson 
235*77d1c127SSebastian Grimberg   @param[in]  rstr         CeedElemRestriction to retrieve curl-conforming orientations
236*77d1c127SSebastian Grimberg   @param[in]  mem_type     Memory type on which to access the array. If the backend uses a different memory type, this will perform a copy (possibly
237*77d1c127SSebastian Grimberg cached).
238*77d1c127SSebastian Grimberg   @param[out] curl_orients Array on memory type mem_type
2397a982d89SJeremy L. Thompson 
2407a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
2417a982d89SJeremy L. Thompson 
242*77d1c127SSebastian Grimberg   @ref User
2437a982d89SJeremy L. Thompson **/
244*77d1c127SSebastian Grimberg int CeedElemRestrictionGetCurlOrientations(CeedElemRestriction rstr, CeedMemType mem_type, const CeedInt **curl_orients) {
245*77d1c127SSebastian Grimberg   CeedCheck(rstr->GetCurlOrientations, rstr->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement GetCurlOrientations");
246*77d1c127SSebastian Grimberg   CeedCall(rstr->GetCurlOrientations(rstr, mem_type, curl_orients));
247*77d1c127SSebastian Grimberg   rstr->num_readers++;
248*77d1c127SSebastian Grimberg   return CEED_ERROR_SUCCESS;
249*77d1c127SSebastian Grimberg }
250*77d1c127SSebastian Grimberg 
251*77d1c127SSebastian Grimberg /**
252*77d1c127SSebastian Grimberg   @brief Restore an orientations array obtained using CeedElemRestrictionGetCurlOrientations()
253*77d1c127SSebastian Grimberg 
254*77d1c127SSebastian Grimberg   @param[in] rstr         CeedElemRestriction to restore
255*77d1c127SSebastian Grimberg   @param[in] curl_orients Array of orientation data
256*77d1c127SSebastian Grimberg 
257*77d1c127SSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
258*77d1c127SSebastian Grimberg 
259*77d1c127SSebastian Grimberg   @ref User
260*77d1c127SSebastian Grimberg **/
261*77d1c127SSebastian Grimberg int CeedElemRestrictionRestoreCurlOrientations(CeedElemRestriction rstr, const CeedInt **curl_orients) {
262*77d1c127SSebastian Grimberg   *curl_orients = NULL;
263*77d1c127SSebastian Grimberg   rstr->num_readers--;
264e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2657a982d89SJeremy L. Thompson }
2667a982d89SJeremy L. Thompson 
2677a982d89SJeremy L. Thompson /**
26849fd234cSJeremy L Thompson 
26949fd234cSJeremy L Thompson   @brief Get the E-vector layout of a CeedElemRestriction
27049fd234cSJeremy L Thompson 
271ea61e9acSJeremy L Thompson   @param[in]  rstr    CeedElemRestriction
272*77d1c127SSebastian Grimberg   @param[out] layout  Variable to store layout array, stored as [nodes, components, elements]. The data for node i, component j, element k in the
273*77d1c127SSebastian Grimberg E-vector is given by i*layout[0] + j*layout[1] + k*layout[2]
27449fd234cSJeremy L Thompson 
27549fd234cSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
27649fd234cSJeremy L Thompson 
27749fd234cSJeremy L Thompson   @ref Backend
27849fd234cSJeremy L Thompson **/
2792b730f8bSJeremy L Thompson int CeedElemRestrictionGetELayout(CeedElemRestriction rstr, CeedInt (*layout)[3]) {
2806574a04fSJeremy L Thompson   CeedCheck(rstr->layout[0], rstr->ceed, CEED_ERROR_MINOR, "ElemRestriction has no layout data");
2812b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < 3; i++) (*layout)[i] = rstr->layout[i];
282e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
28349fd234cSJeremy L Thompson }
28449fd234cSJeremy L Thompson 
28549fd234cSJeremy L Thompson /**
28649fd234cSJeremy L Thompson 
28749fd234cSJeremy L Thompson   @brief Set the E-vector layout of a CeedElemRestriction
28849fd234cSJeremy L Thompson 
289ea61e9acSJeremy L Thompson   @param[in] rstr   CeedElemRestriction
290ea61e9acSJeremy L Thompson   @param[in] layout Variable to containing layout array, stored as [nodes, components, elements].
291ea61e9acSJeremy 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]
29249fd234cSJeremy L Thompson 
29349fd234cSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
29449fd234cSJeremy L Thompson 
29549fd234cSJeremy L Thompson   @ref Backend
29649fd234cSJeremy L Thompson **/
2972b730f8bSJeremy L Thompson int CeedElemRestrictionSetELayout(CeedElemRestriction rstr, CeedInt layout[3]) {
2982b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < 3; i++) rstr->layout[i] = layout[i];
299e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
30049fd234cSJeremy L Thompson }
30149fd234cSJeremy L Thompson 
30249fd234cSJeremy L Thompson /**
3037a982d89SJeremy L. Thompson   @brief Get the backend data of a CeedElemRestriction
3047a982d89SJeremy L. Thompson 
305ea61e9acSJeremy L Thompson   @param[in]  rstr CeedElemRestriction
3067a982d89SJeremy L. Thompson   @param[out] data Variable to store data
3077a982d89SJeremy L. Thompson 
3087a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3097a982d89SJeremy L. Thompson 
3107a982d89SJeremy L. Thompson   @ref Backend
3117a982d89SJeremy L. Thompson **/
312777ff853SJeremy L Thompson int CeedElemRestrictionGetData(CeedElemRestriction rstr, void *data) {
313777ff853SJeremy L Thompson   *(void **)data = rstr->data;
314e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3157a982d89SJeremy L. Thompson }
3167a982d89SJeremy L. Thompson 
3177a982d89SJeremy L. Thompson /**
3187a982d89SJeremy L. Thompson   @brief Set the backend data of a CeedElemRestriction
3197a982d89SJeremy L. Thompson 
320ea61e9acSJeremy L Thompson   @param[in,out] rstr CeedElemRestriction
321ea61e9acSJeremy L Thompson   @param[in]     data Data to set
3227a982d89SJeremy L. Thompson 
3237a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3247a982d89SJeremy L. Thompson 
3257a982d89SJeremy L. Thompson   @ref Backend
3267a982d89SJeremy L. Thompson **/
327777ff853SJeremy L Thompson int CeedElemRestrictionSetData(CeedElemRestriction rstr, void *data) {
328777ff853SJeremy L Thompson   rstr->data = data;
329e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3307a982d89SJeremy L. Thompson }
3317a982d89SJeremy L. Thompson 
33234359f16Sjeremylt /**
33334359f16Sjeremylt   @brief Increment the reference counter for a CeedElemRestriction
33434359f16Sjeremylt 
335ea61e9acSJeremy L Thompson   @param[in,out] rstr ElemRestriction to increment the reference counter
33634359f16Sjeremylt 
33734359f16Sjeremylt   @return An error code: 0 - success, otherwise - failure
33834359f16Sjeremylt 
33934359f16Sjeremylt   @ref Backend
34034359f16Sjeremylt **/
3419560d06aSjeremylt int CeedElemRestrictionReference(CeedElemRestriction rstr) {
34234359f16Sjeremylt   rstr->ref_count++;
34334359f16Sjeremylt   return CEED_ERROR_SUCCESS;
34434359f16Sjeremylt }
34534359f16Sjeremylt 
3466e15d496SJeremy L Thompson /**
3476e15d496SJeremy L Thompson   @brief Estimate number of FLOPs required to apply CeedElemRestriction in t_mode
3486e15d496SJeremy L Thompson 
349ea61e9acSJeremy L Thompson   @param[in]  rstr   ElemRestriction to estimate FLOPs for
350ea61e9acSJeremy L Thompson   @param[in]  t_mode Apply restriction or transpose
351ea61e9acSJeremy L Thompson   @param[out] flops  Address of variable to hold FLOPs estimate
3526e15d496SJeremy L Thompson 
3536e15d496SJeremy L Thompson   @ref Backend
3546e15d496SJeremy L Thompson **/
3552b730f8bSJeremy L Thompson int CeedElemRestrictionGetFlopsEstimate(CeedElemRestriction rstr, CeedTransposeMode t_mode, CeedSize *flops) {
356*77d1c127SSebastian Grimberg   const bool    *orients      = NULL;
357*77d1c127SSebastian Grimberg   const CeedInt *curl_orients = NULL;
3582b730f8bSJeremy L Thompson   CeedInt        e_size = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp, scale = 0;
3596e15d496SJeremy L Thompson 
360*77d1c127SSebastian Grimberg   CeedCall(CeedElemRestrictionGetOrientations(rstr, CEED_MEM_HOST, &orients));
361*77d1c127SSebastian Grimberg   CeedCall(CeedElemRestrictionGetCurlOrientations(rstr, CEED_MEM_HOST, &curl_orients));
362*77d1c127SSebastian Grimberg   if (t_mode == CEED_TRANSPOSE) {
363*77d1c127SSebastian Grimberg     if (!orients && !curl_orients) {
364*77d1c127SSebastian Grimberg       scale = 1;
365*77d1c127SSebastian Grimberg     } else if (!curl_orients) {
366*77d1c127SSebastian Grimberg       scale = 2;
367*77d1c127SSebastian Grimberg     } else {
368*77d1c127SSebastian Grimberg       scale = 6;
3696e15d496SJeremy L Thompson     }
370*77d1c127SSebastian Grimberg   } else {
371*77d1c127SSebastian Grimberg     if (!orients && !curl_orients) {
372*77d1c127SSebastian Grimberg       scale = 0;
373*77d1c127SSebastian Grimberg     } else if (!curl_orients) {
374*77d1c127SSebastian Grimberg       scale = 1;
375*77d1c127SSebastian Grimberg     } else {
376*77d1c127SSebastian Grimberg       scale = 5;
377*77d1c127SSebastian Grimberg     }
378*77d1c127SSebastian Grimberg   }
379*77d1c127SSebastian Grimberg   CeedCall(CeedElemRestrictionRestoreOrientations(rstr, &orients));
380*77d1c127SSebastian Grimberg   CeedCall(CeedElemRestrictionRestoreCurlOrientations(rstr, &curl_orients));
3816e15d496SJeremy L Thompson   *flops = e_size * scale;
3826e15d496SJeremy L Thompson 
3836e15d496SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3846e15d496SJeremy L Thompson }
3856e15d496SJeremy L Thompson 
3867a982d89SJeremy L. Thompson /// @}
3877a982d89SJeremy L. Thompson 
38815910d16Sjeremylt /// @cond DOXYGEN_SKIP
38915910d16Sjeremylt static struct CeedElemRestriction_private ceed_elemrestriction_none;
39015910d16Sjeremylt /// @endcond
39115910d16Sjeremylt 
3927a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
3937a982d89SJeremy L. Thompson /// CeedElemRestriction Public API
3947a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
3957a982d89SJeremy L. Thompson /// @addtogroup CeedElemRestrictionUser
396d7b241e6Sjeremylt /// @{
397d7b241e6Sjeremylt 
3987a982d89SJeremy L. Thompson /// Indicate that the stride is determined by the backend
39945f1e315Sjeremylt const CeedInt CEED_STRIDES_BACKEND[3] = {0};
4007a982d89SJeremy L. Thompson 
4014cc79fe7SJed Brown /// Indicate that no CeedElemRestriction is provided by the user
4022b730f8bSJeremy L Thompson const CeedElemRestriction CEED_ELEMRESTRICTION_NONE = &ceed_elemrestriction_none;
4037a982d89SJeremy L. Thompson 
404d7b241e6Sjeremylt /**
405b11c1e72Sjeremylt   @brief Create a CeedElemRestriction
406d7b241e6Sjeremylt 
407ea61e9acSJeremy L Thompson   @param[in]  ceed        Ceed object where the CeedElemRestriction will be created
408ea61e9acSJeremy L Thompson   @param[in]  num_elem    Number of elements described in the @a offsets array
409ea61e9acSJeremy L Thompson   @param[in]  elem_size   Size (number of "nodes") per element
410ea61e9acSJeremy L Thompson   @param[in]  num_comp    Number of field components per interpolation node (1 for scalar fields)
411*77d1c127SSebastian Grimberg   @param[in]  comp_stride Stride between components for the same L-vector "node". Data for node i, component j, element k can be found in the L-vector
412*77d1c127SSebastian Grimberg at index offsets[i + k*elem_size] + j*comp_stride.
413*77d1c127SSebastian Grimberg   @param[in]  l_size      The size of the L-vector. This vector may be larger than the elements and fields given by this restriction.
414ea61e9acSJeremy L Thompson   @param[in]  mem_type    Memory type of the @a offsets array, see CeedMemType
415ea61e9acSJeremy L Thompson   @param[in]  copy_mode   Copy mode for the @a offsets array, see CeedCopyMode
416*77d1c127SSebastian Grimberg   @param[in]  offsets     Array of shape [@a num_elem, @a elem_size]. Row i holds the ordered list of the offsets (into the input CeedVector) for the
417*77d1c127SSebastian Grimberg unknowns corresponding to element i, where 0 <= i < @a num_elem. All offsets must be in the range [0, @a l_size - 1].
418ea61e9acSJeremy L Thompson   @param[out] rstr        Address of the variable where the newly created CeedElemRestriction will be stored
419d7b241e6Sjeremylt 
420b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
421dfdf5a53Sjeremylt 
4227a982d89SJeremy L. Thompson   @ref User
423b11c1e72Sjeremylt **/
4242b730f8bSJeremy L Thompson int CeedElemRestrictionCreate(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedInt comp_stride, CeedSize l_size,
4252b730f8bSJeremy L Thompson                               CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, CeedElemRestriction *rstr) {
4265fe0d4faSjeremylt   if (!ceed->ElemRestrictionCreate) {
4275fe0d4faSjeremylt     Ceed delegate;
4286574a04fSJeremy L Thompson 
4292b730f8bSJeremy L Thompson     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"));
430*77d1c127SSebastian Grimberg     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreate");
4312b730f8bSJeremy L Thompson     CeedCall(CeedElemRestrictionCreate(delegate, num_elem, elem_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, rstr));
432e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
4335fe0d4faSjeremylt   }
4345fe0d4faSjeremylt 
4356574a04fSJeremy L Thompson   CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1");
4366574a04fSJeremy L Thompson   CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component");
4376574a04fSJeremy L Thompson   CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction component stride must be at least 1");
438e022e1f8SJeremy L Thompson 
4392b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, rstr));
440db002c03SJeremy L Thompson   CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed));
441d1d35e2fSjeremylt   (*rstr)->ref_count   = 1;
442d1d35e2fSjeremylt   (*rstr)->num_elem    = num_elem;
443d1d35e2fSjeremylt   (*rstr)->elem_size   = elem_size;
444d1d35e2fSjeremylt   (*rstr)->num_comp    = num_comp;
445d1d35e2fSjeremylt   (*rstr)->comp_stride = comp_stride;
446d1d35e2fSjeremylt   (*rstr)->l_size      = l_size;
447d1d35e2fSjeremylt   (*rstr)->num_blk     = num_elem;
448d1d35e2fSjeremylt   (*rstr)->blk_size    = 1;
4492b730f8bSJeremy L Thompson   CeedCall(ceed->ElemRestrictionCreate(mem_type, copy_mode, offsets, *rstr));
450e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
451d7b241e6Sjeremylt }
452d7b241e6Sjeremylt 
453d7b241e6Sjeremylt /**
454*77d1c127SSebastian Grimberg   @brief Create a CeedElemRestriction with orientation signs
455fc0567d9Srezgarshakeri 
456ea61e9acSJeremy L Thompson   @param[in]  ceed        Ceed object where the CeedElemRestriction will be created
457ea61e9acSJeremy L Thompson   @param[in]  num_elem    Number of elements described in the @a offsets array
458ea61e9acSJeremy L Thompson   @param[in]  elem_size   Size (number of "nodes") per element
459ea61e9acSJeremy L Thompson   @param[in]  num_comp    Number of field components per interpolation node (1 for scalar fields)
460*77d1c127SSebastian Grimberg   @param[in]  comp_stride Stride between components for the same L-vector "node". Data for node i, component j, element k can be found in the L-vector
461*77d1c127SSebastian Grimberg at index offsets[i + k*elem_size] + j*comp_stride.
462*77d1c127SSebastian Grimberg   @param[in]  l_size      The size of the L-vector. This vector may be larger than the elements and fields given by this restriction.
463ea61e9acSJeremy L Thompson   @param[in]  mem_type    Memory type of the @a offsets array, see CeedMemType
464ea61e9acSJeremy L Thompson   @param[in]  copy_mode   Copy mode for the @a offsets array, see CeedCopyMode
465*77d1c127SSebastian Grimberg   @param[in]  offsets     Array of shape [@a num_elem, @a elem_size]. Row i holds the ordered list of the offsets (into the input CeedVector) for the
466*77d1c127SSebastian Grimberg unknowns corresponding to element i, where 0 <= i < @a num_elem. All offsets must be in the range [0, @a l_size - 1].
467*77d1c127SSebastian Grimberg   @param[in]  orients     Array of shape [@a num_elem, @a elem_size] with bool false for positively oriented and true to flip the orientation.
468ea61e9acSJeremy L Thompson   @param[out] rstr        Address of the variable where the newly created CeedElemRestriction will be stored
469fc0567d9Srezgarshakeri 
470fc0567d9Srezgarshakeri   @return An error code: 0 - success, otherwise - failure
471fc0567d9Srezgarshakeri 
472fc0567d9Srezgarshakeri   @ref User
473fc0567d9Srezgarshakeri **/
4742b730f8bSJeremy L Thompson int CeedElemRestrictionCreateOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedInt comp_stride, CeedSize l_size,
475*77d1c127SSebastian Grimberg                                       CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, const bool *orients,
476fc0567d9Srezgarshakeri                                       CeedElemRestriction *rstr) {
477c7745053SRezgar Shakeri   if (!ceed->ElemRestrictionCreateOriented) {
478fc0567d9Srezgarshakeri     Ceed delegate;
4796574a04fSJeremy L Thompson 
4802b730f8bSJeremy L Thompson     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"));
4816574a04fSJeremy L Thompson     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreateOriented");
4822b730f8bSJeremy L Thompson     CeedCall(
483*77d1c127SSebastian Grimberg         CeedElemRestrictionCreateOriented(delegate, num_elem, elem_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, orients, rstr));
484fc0567d9Srezgarshakeri     return CEED_ERROR_SUCCESS;
485fc0567d9Srezgarshakeri   }
486fc0567d9Srezgarshakeri 
4876574a04fSJeremy L Thompson   CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1");
4886574a04fSJeremy L Thompson   CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component");
4896574a04fSJeremy L Thompson   CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction component stride must be at least 1");
490e022e1f8SJeremy L Thompson 
4912b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, rstr));
492db002c03SJeremy L Thompson   CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed));
493fc0567d9Srezgarshakeri   (*rstr)->ref_count   = 1;
494fc0567d9Srezgarshakeri   (*rstr)->num_elem    = num_elem;
495fc0567d9Srezgarshakeri   (*rstr)->elem_size   = elem_size;
496fc0567d9Srezgarshakeri   (*rstr)->num_comp    = num_comp;
497fc0567d9Srezgarshakeri   (*rstr)->comp_stride = comp_stride;
498fc0567d9Srezgarshakeri   (*rstr)->l_size      = l_size;
499fc0567d9Srezgarshakeri   (*rstr)->num_blk     = num_elem;
500fc0567d9Srezgarshakeri   (*rstr)->blk_size    = 1;
501*77d1c127SSebastian Grimberg   return CEED_ERROR_SUCCESS;
502*77d1c127SSebastian Grimberg }
503*77d1c127SSebastian Grimberg 
504*77d1c127SSebastian Grimberg /**
505*77d1c127SSebastian Grimberg   @brief Create a CeedElemRestriction with a general tridiagonal transformation matrix for curl-conforming elements
506*77d1c127SSebastian Grimberg 
507*77d1c127SSebastian Grimberg   @param[in]  ceed         Ceed object where the CeedElemRestriction will be created
508*77d1c127SSebastian Grimberg   @param[in]  num_elem     Number of elements described in the @a offsets array
509*77d1c127SSebastian Grimberg   @param[in]  elem_size    Size (number of "nodes") per element
510*77d1c127SSebastian Grimberg   @param[in]  num_comp     Number of field components per interpolation node (1 for scalar fields)
511*77d1c127SSebastian Grimberg   @param[in]  comp_stride  Stride between components for the same L-vector "node". Data for node i, component j, element k can be found in the
512*77d1c127SSebastian Grimberg L-vector at index offsets[i + k*elem_size] + j*comp_stride.
513*77d1c127SSebastian Grimberg   @param[in]  l_size       The size of the L-vector. This vector may be larger than the elements and fields given by this restriction.
514*77d1c127SSebastian Grimberg   @param[in]  mem_type     Memory type of the @a offsets array, see CeedMemType
515*77d1c127SSebastian Grimberg   @param[in]  copy_mode    Copy mode for the @a offsets array, see CeedCopyMode
516*77d1c127SSebastian Grimberg   @param[in]  offsets      Array of shape [@a num_elem, @a elem_size]. Row i holds the ordered list of the offsets (into the input CeedVector) for the
517*77d1c127SSebastian Grimberg unknowns corresponding to element i, where 0 <= i < @a num_elem. All offsets must be in the range [0, @a l_size - 1].
518*77d1c127SSebastian Grimberg   @param[in]  curl_orients Array of shape [@a num_elem, @a 3 * elem_size] representing a row-major tridiagonal matrix (curl_orients[0] =
519*77d1c127SSebastian Grimberg curl_orients[(i + 1) * 3 * elem_size - 1] = 0, where 0 <= i < @a num_elem) which is applied to the element unknowns upon restriction. This orientation
520*77d1c127SSebastian Grimberg matrix allows for pairs of face degrees of freedom on elements for H(curl) spaces to be coupled in the element restriction operation, which is a way
521*77d1c127SSebastian Grimberg to resolve face orientation issues for 3D meshes (https://dl.acm.org/doi/pdf/10.1145/3524456).
522*77d1c127SSebastian Grimberg   @param[out] rstr         Address of the variable where the newly created CeedElemRestriction will be stored
523*77d1c127SSebastian Grimberg 
524*77d1c127SSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
525*77d1c127SSebastian Grimberg 
526*77d1c127SSebastian Grimberg   @ref User
527*77d1c127SSebastian Grimberg **/
528*77d1c127SSebastian Grimberg int CeedElemRestrictionCreateCurlOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedInt comp_stride, CeedSize l_size,
529*77d1c127SSebastian Grimberg                                           CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, const CeedInt *curl_orients,
530*77d1c127SSebastian Grimberg                                           CeedElemRestriction *rstr) {
531*77d1c127SSebastian Grimberg   if (!ceed->ElemRestrictionCreateCurlOriented) {
532*77d1c127SSebastian Grimberg     Ceed delegate;
533*77d1c127SSebastian Grimberg 
534*77d1c127SSebastian Grimberg     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"));
535*77d1c127SSebastian Grimberg     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreateCurlOriented");
536*77d1c127SSebastian Grimberg     CeedCall(CeedElemRestrictionCreateCurlOriented(delegate, num_elem, elem_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets,
537*77d1c127SSebastian Grimberg                                                    curl_orients, rstr));
538*77d1c127SSebastian Grimberg     return CEED_ERROR_SUCCESS;
539*77d1c127SSebastian Grimberg   }
540*77d1c127SSebastian Grimberg 
541*77d1c127SSebastian Grimberg   CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1");
542*77d1c127SSebastian Grimberg   CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component");
543*77d1c127SSebastian Grimberg   CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction component stride must be at least 1");
544*77d1c127SSebastian Grimberg 
545*77d1c127SSebastian Grimberg   CeedCall(CeedCalloc(1, rstr));
546*77d1c127SSebastian Grimberg   (*rstr)->ceed = ceed;
547*77d1c127SSebastian Grimberg   CeedCall(CeedReference(ceed));
548*77d1c127SSebastian Grimberg   (*rstr)->ref_count   = 1;
549*77d1c127SSebastian Grimberg   (*rstr)->num_elem    = num_elem;
550*77d1c127SSebastian Grimberg   (*rstr)->elem_size   = elem_size;
551*77d1c127SSebastian Grimberg   (*rstr)->num_comp    = num_comp;
552*77d1c127SSebastian Grimberg   (*rstr)->comp_stride = comp_stride;
553*77d1c127SSebastian Grimberg   (*rstr)->l_size      = l_size;
554*77d1c127SSebastian Grimberg   (*rstr)->num_blk     = num_elem;
555*77d1c127SSebastian Grimberg   (*rstr)->blk_size    = 1;
556*77d1c127SSebastian Grimberg   CeedCall(ceed->ElemRestrictionCreateCurlOriented(mem_type, copy_mode, offsets, curl_orients, *rstr));
557fc0567d9Srezgarshakeri   return CEED_ERROR_SUCCESS;
558fc0567d9Srezgarshakeri }
559fc0567d9Srezgarshakeri 
560fc0567d9Srezgarshakeri /**
5617509a596Sjeremylt   @brief Create a strided CeedElemRestriction
562d7b241e6Sjeremylt 
563ea61e9acSJeremy L Thompson   @param[in]  ceed      Ceed object where the CeedElemRestriction will be created
564ea61e9acSJeremy L Thompson   @param[in]  num_elem  Number of elements described by the restriction
565ea61e9acSJeremy L Thompson   @param[in]  elem_size Size (number of "nodes") per element
566ea61e9acSJeremy L Thompson   @param[in]  num_comp  Number of field components per interpolation "node" (1 for scalar fields)
567*77d1c127SSebastian Grimberg   @param[in]  l_size    The size of the L-vector. This vector may be larger than the elements and fields given by this restriction.
568*77d1c127SSebastian Grimberg   @param[in]  strides   Array for strides between [nodes, components, elements]. Data for node i, component j, element k can be found in the L-vector
569*77d1c127SSebastian Grimberg at index i*strides[0] + j*strides[1] + k*strides[2]. @a CEED_STRIDES_BACKEND may be used with vectors created by a Ceed backend.
570ea61e9acSJeremy L Thompson   @param[out] rstr      Address of the variable where the newly created CeedElemRestriction will be stored
571d7b241e6Sjeremylt 
572b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
573dfdf5a53Sjeremylt 
5747a982d89SJeremy L. Thompson   @ref User
575b11c1e72Sjeremylt **/
5762b730f8bSJeremy L Thompson int CeedElemRestrictionCreateStrided(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedSize l_size, const CeedInt strides[3],
577f90c8643Sjeremylt                                      CeedElemRestriction *rstr) {
5785fe0d4faSjeremylt   if (!ceed->ElemRestrictionCreate) {
5795fe0d4faSjeremylt     Ceed delegate;
580b04eb3d9SSebastian Grimberg 
5812b730f8bSJeremy L Thompson     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"));
582*77d1c127SSebastian Grimberg     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreateStrided");
5832b730f8bSJeremy L Thompson     CeedCall(CeedElemRestrictionCreateStrided(delegate, num_elem, elem_size, num_comp, l_size, strides, rstr));
584e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
5855fe0d4faSjeremylt   }
5865fe0d4faSjeremylt 
5876574a04fSJeremy L Thompson   CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1");
5886574a04fSJeremy L Thompson   CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component");
589e022e1f8SJeremy L Thompson 
5902b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, rstr));
591db002c03SJeremy L Thompson   CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed));
592d1d35e2fSjeremylt   (*rstr)->ref_count = 1;
593d1d35e2fSjeremylt   (*rstr)->num_elem  = num_elem;
594d1d35e2fSjeremylt   (*rstr)->elem_size = elem_size;
595d1d35e2fSjeremylt   (*rstr)->num_comp  = num_comp;
596d1d35e2fSjeremylt   (*rstr)->l_size    = l_size;
597d1d35e2fSjeremylt   (*rstr)->num_blk   = num_elem;
598d1d35e2fSjeremylt   (*rstr)->blk_size  = 1;
5992b730f8bSJeremy L Thompson   CeedCall(CeedMalloc(3, &(*rstr)->strides));
6002b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < 3; i++) (*rstr)->strides[i] = strides[i];
6012b730f8bSJeremy L Thompson   CeedCall(ceed->ElemRestrictionCreate(CEED_MEM_HOST, CEED_OWN_POINTER, NULL, *rstr));
602e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
603d7b241e6Sjeremylt }
604d7b241e6Sjeremylt 
605d7b241e6Sjeremylt /**
606b11c1e72Sjeremylt   @brief Create a blocked CeedElemRestriction, typically only called by backends
607d7b241e6Sjeremylt 
608ea61e9acSJeremy L Thompson   @param[in]  ceed        Ceed object where the CeedElemRestriction will be created.
609ea61e9acSJeremy L Thompson   @param[in]  num_elem    Number of elements described in the @a offsets array.
610ea61e9acSJeremy L Thompson   @param[in]  elem_size   Size (number of unknowns) per element
611ea61e9acSJeremy L Thompson   @param[in]  blk_size    Number of elements in a block
612ea61e9acSJeremy L Thompson   @param[in]  num_comp    Number of field components per interpolation node (1 for scalar fields)
613*77d1c127SSebastian Grimberg   @param[in]  comp_stride Stride between components for the same L-vector "node". Data for node i, component j, element k can be found in the L-vector
614*77d1c127SSebastian Grimberg  at index offsets[i + k*elem_size] + j*comp_stride.
615*77d1c127SSebastian Grimberg   @param[in]  l_size      The size of the L-vector. This vector may be larger than the elements and fields given by this restriction.
616ea61e9acSJeremy L Thompson   @param[in]  mem_type    Memory type of the @a offsets array, see CeedMemType
617ea61e9acSJeremy L Thompson   @param[in]  copy_mode   Copy mode for the @a offsets array, see CeedCopyMode
618*77d1c127SSebastian Grimberg   @param[in]  offsets     Array of shape [@a num_elem, @a elem_size]. Row i holds the ordered list of the offsets (into the input CeedVector) for the
619*77d1c127SSebastian Grimberg  unknowns corresponding to element i, where 0 <= i < @a num_elem. All offsets must be in the range [0, @a l_size - 1]. The backend will permute and
620*77d1c127SSebastian Grimberg  pad this array to the desired ordering for the blocksize, which is typically given by the backend. The default reordering is to interlace elements.
621ea61e9acSJeremy L Thompson   @param[out] rstr        Address of the variable where the newly created CeedElemRestriction will be stored
622d7b241e6Sjeremylt 
623b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
624dfdf5a53Sjeremylt 
6257a982d89SJeremy L. Thompson   @ref Backend
626b11c1e72Sjeremylt  **/
6272b730f8bSJeremy L Thompson int CeedElemRestrictionCreateBlocked(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt blk_size, CeedInt num_comp, CeedInt comp_stride,
6282b730f8bSJeremy L Thompson                                      CeedSize l_size, CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets,
6294ce2993fSjeremylt                                      CeedElemRestriction *rstr) {
630d1d35e2fSjeremylt   CeedInt *blk_offsets;
631d1d35e2fSjeremylt   CeedInt  num_blk = (num_elem / blk_size) + !!(num_elem % blk_size);
632d7b241e6Sjeremylt 
6335fe0d4faSjeremylt   if (!ceed->ElemRestrictionCreateBlocked) {
6345fe0d4faSjeremylt     Ceed delegate;
6356574a04fSJeremy L Thompson 
6362b730f8bSJeremy L Thompson     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"));
6376402da51SJeremy L Thompson     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreateBlocked");
6382b730f8bSJeremy L Thompson     CeedCall(
6392b730f8bSJeremy L Thompson         CeedElemRestrictionCreateBlocked(delegate, num_elem, elem_size, blk_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, rstr));
640e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
6415fe0d4faSjeremylt   }
642d7b241e6Sjeremylt 
6436574a04fSJeremy L Thompson   CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1");
6446574a04fSJeremy L Thompson   CeedCheck(blk_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1");
6456574a04fSJeremy L Thompson   CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component");
6466574a04fSJeremy L Thompson   CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction component stride must be at least 1");
647e022e1f8SJeremy L Thompson 
6482b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(num_blk * blk_size * elem_size, &blk_offsets));
6492b730f8bSJeremy L Thompson   CeedCall(CeedPermutePadOffsets(offsets, blk_offsets, num_blk, num_elem, blk_size, elem_size));
650d7b241e6Sjeremylt 
651db002c03SJeremy L Thompson   CeedCall(CeedCalloc(1, rstr));
652db002c03SJeremy L Thompson   CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed));
653d1d35e2fSjeremylt   (*rstr)->ref_count   = 1;
654d1d35e2fSjeremylt   (*rstr)->num_elem    = num_elem;
655d1d35e2fSjeremylt   (*rstr)->elem_size   = elem_size;
656d1d35e2fSjeremylt   (*rstr)->num_comp    = num_comp;
657d1d35e2fSjeremylt   (*rstr)->comp_stride = comp_stride;
658d1d35e2fSjeremylt   (*rstr)->l_size      = l_size;
659d1d35e2fSjeremylt   (*rstr)->num_blk     = num_blk;
660d1d35e2fSjeremylt   (*rstr)->blk_size    = blk_size;
6612b730f8bSJeremy L Thompson   CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, (const CeedInt *)blk_offsets, *rstr));
662d1d35e2fSjeremylt   if (copy_mode == CEED_OWN_POINTER) {
6632b730f8bSJeremy L Thompson     CeedCall(CeedFree(&offsets));
6641d102b48SJeremy L Thompson   }
665e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
666d7b241e6Sjeremylt }
667d7b241e6Sjeremylt 
668b11c1e72Sjeremylt /**
669*77d1c127SSebastian Grimberg   @brief Create a blocked oriented CeedElemRestriction, typically only called by backends
670*77d1c127SSebastian Grimberg 
671*77d1c127SSebastian Grimberg   @param[in]  ceed        Ceed object where the CeedElemRestriction will be created.
672*77d1c127SSebastian Grimberg   @param[in]  num_elem    Number of elements described in the @a offsets array.
673*77d1c127SSebastian Grimberg   @param[in]  elem_size   Size (number of unknowns) per element
674*77d1c127SSebastian Grimberg   @param[in]  blk_size    Number of elements in a block
675*77d1c127SSebastian Grimberg   @param[in]  num_comp    Number of field components per interpolation node (1 for scalar fields)
676*77d1c127SSebastian Grimberg   @param[in]  comp_stride Stride between components for the same L-vector "node". Data for node i, component j, element k can be found in the L-vector
677*77d1c127SSebastian Grimberg  at index offsets[i + k*elem_size] + j*comp_stride.
678*77d1c127SSebastian Grimberg   @param[in]  l_size      The size of the L-vector. This vector may be larger than the elements and fields given by this restriction.
679*77d1c127SSebastian Grimberg   @param[in]  mem_type    Memory type of the @a offsets array, see CeedMemType
680*77d1c127SSebastian Grimberg   @param[in]  copy_mode   Copy mode for the @a offsets array, see CeedCopyMode
681*77d1c127SSebastian Grimberg   @param[in]  offsets     Array of shape [@a num_elem, @a elem_size]. Row i holds the ordered list of the offsets (into the input CeedVector) for the
682*77d1c127SSebastian Grimberg  unknowns corresponding to element i, where 0 <= i < @a num_elem. All offsets must be in the range [0, @a l_size - 1]. The backend will permute and
683*77d1c127SSebastian Grimberg  pad this array to the desired ordering for the blocksize, which is typically given by the backend. The default reordering is to interlace elements.
684*77d1c127SSebastian Grimberg   @param[in]  orients     Array of shape [@a num_elem, @a elem_size] with bool false for positively oriented and true to flip the orientation. Will
685*77d1c127SSebastian Grimberg  also be permuted and padded similarly to offsets.
686*77d1c127SSebastian Grimberg   @param[out] rstr        Address of the variable where the newly created CeedElemRestriction will be stored
687*77d1c127SSebastian Grimberg 
688*77d1c127SSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
689*77d1c127SSebastian Grimberg 
690*77d1c127SSebastian Grimberg   @ref Backend
691*77d1c127SSebastian Grimberg  **/
692*77d1c127SSebastian Grimberg int CeedElemRestrictionCreateBlockedOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt blk_size, CeedInt num_comp, CeedInt comp_stride,
693*77d1c127SSebastian Grimberg                                              CeedSize l_size, CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets,
694*77d1c127SSebastian Grimberg                                              const bool *orients, CeedElemRestriction *rstr) {
695*77d1c127SSebastian Grimberg   CeedInt *blk_offsets;
696*77d1c127SSebastian Grimberg   bool    *blk_orients;
697*77d1c127SSebastian Grimberg   CeedInt  num_blk = (num_elem / blk_size) + !!(num_elem % blk_size);
698*77d1c127SSebastian Grimberg 
699*77d1c127SSebastian Grimberg   if (!ceed->ElemRestrictionCreateBlockedOriented) {
700*77d1c127SSebastian Grimberg     Ceed delegate;
701*77d1c127SSebastian Grimberg 
702*77d1c127SSebastian Grimberg     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"));
703*77d1c127SSebastian Grimberg     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreateBlockedOriented");
704*77d1c127SSebastian Grimberg     CeedCall(CeedElemRestrictionCreateBlockedOriented(delegate, num_elem, elem_size, blk_size, num_comp, comp_stride, l_size, mem_type, copy_mode,
705*77d1c127SSebastian Grimberg                                                       offsets, orients, rstr));
706*77d1c127SSebastian Grimberg     return CEED_ERROR_SUCCESS;
707*77d1c127SSebastian Grimberg   }
708*77d1c127SSebastian Grimberg 
709*77d1c127SSebastian Grimberg   CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1");
710*77d1c127SSebastian Grimberg   CeedCheck(blk_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1");
711*77d1c127SSebastian Grimberg   CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component");
712*77d1c127SSebastian Grimberg   CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction component stride must be at least 1");
713*77d1c127SSebastian Grimberg 
714*77d1c127SSebastian Grimberg   CeedCall(CeedCalloc(1, rstr));
715*77d1c127SSebastian Grimberg 
716*77d1c127SSebastian Grimberg   CeedCall(CeedCalloc(num_blk * blk_size * elem_size, &blk_offsets));
717*77d1c127SSebastian Grimberg   CeedCall(CeedCalloc(num_blk * blk_size * elem_size, &blk_orients));
718*77d1c127SSebastian Grimberg   CeedCall(CeedPermutePadOffsets(offsets, blk_offsets, num_blk, num_elem, blk_size, elem_size));
719*77d1c127SSebastian Grimberg   CeedCall(CeedPermutePadOrientations(orients, blk_orients, num_blk, num_elem, blk_size, elem_size));
720*77d1c127SSebastian Grimberg 
721*77d1c127SSebastian Grimberg   (*rstr)->ceed = ceed;
722*77d1c127SSebastian Grimberg   CeedCall(CeedReference(ceed));
723*77d1c127SSebastian Grimberg   (*rstr)->ref_count   = 1;
724*77d1c127SSebastian Grimberg   (*rstr)->num_elem    = num_elem;
725*77d1c127SSebastian Grimberg   (*rstr)->elem_size   = elem_size;
726*77d1c127SSebastian Grimberg   (*rstr)->num_comp    = num_comp;
727*77d1c127SSebastian Grimberg   (*rstr)->comp_stride = comp_stride;
728*77d1c127SSebastian Grimberg   (*rstr)->l_size      = l_size;
729*77d1c127SSebastian Grimberg   (*rstr)->num_blk     = num_blk;
730*77d1c127SSebastian Grimberg   (*rstr)->blk_size    = blk_size;
731*77d1c127SSebastian Grimberg   CeedCall(
732*77d1c127SSebastian Grimberg       ceed->ElemRestrictionCreateBlockedOriented(CEED_MEM_HOST, CEED_OWN_POINTER, (const CeedInt *)blk_offsets, (const bool *)blk_orients, *rstr));
733*77d1c127SSebastian Grimberg   if (copy_mode == CEED_OWN_POINTER) {
734*77d1c127SSebastian Grimberg     CeedCall(CeedFree(&offsets));
735*77d1c127SSebastian Grimberg   }
736*77d1c127SSebastian Grimberg   return CEED_ERROR_SUCCESS;
737*77d1c127SSebastian Grimberg }
738*77d1c127SSebastian Grimberg 
739*77d1c127SSebastian Grimberg /**
740*77d1c127SSebastian Grimberg   @brief Create a blocked curl-oriented CeedElemRestriction, typically only called by backends
741*77d1c127SSebastian Grimberg 
742*77d1c127SSebastian Grimberg   @param[in]  ceed         Ceed object where the CeedElemRestriction will be created.
743*77d1c127SSebastian Grimberg   @param[in]  num_elem     Number of elements described in the @a offsets array.
744*77d1c127SSebastian Grimberg   @param[in]  elem_size    Size (number of unknowns) per element
745*77d1c127SSebastian Grimberg   @param[in]  blk_size     Number of elements in a block
746*77d1c127SSebastian Grimberg   @param[in]  num_comp     Number of field components per interpolation node (1 for scalar fields)
747*77d1c127SSebastian Grimberg   @param[in]  comp_stride  Stride between components for the same L-vector "node". Data for node i, component j, element k can be found in the
748*77d1c127SSebastian Grimberg  L-vector at index offsets[i + k*elem_size] + j*comp_stride.
749*77d1c127SSebastian Grimberg   @param[in]  l_size       The size of the L-vector. This vector may be larger than the elements and fields given by this restriction.
750*77d1c127SSebastian Grimberg   @param[in]  mem_type     Memory type of the @a offsets array, see CeedMemType
751*77d1c127SSebastian Grimberg   @param[in]  copy_mode    Copy mode for the @a offsets array, see CeedCopyMode
752*77d1c127SSebastian Grimberg   @param[in]  offsets      Array of shape [@a num_elem, @a elem_size]. Row i holds the ordered list of the offsets (into the input CeedVector) for the
753*77d1c127SSebastian Grimberg  unknowns corresponding to element i, where 0 <= i < @a num_elem. All offsets must be in the range [0, @a l_size - 1]. The backend will permute and
754*77d1c127SSebastian Grimberg  pad this array to the desired ordering for the blocksize, which is typically given by the backend. The default reordering is to interlace elements.
755*77d1c127SSebastian Grimberg    @param[in]  curl_orients Array of shape [@a num_elem, @a 3 * elem_size] representing a row-major tridiagonal matrix (curl_orients[0] =
756*77d1c127SSebastian Grimberg curl_orients[(i + 1) * 3 * elem_size - 1] = 0, where 0 <= i < @a num_elem) which is applied to the element unknowns upon restriction. This orientation
757*77d1c127SSebastian Grimberg matrix allows for pairs of face degrees of freedom on elements for H(curl) spaces to be coupled in the element restriction operation, which is a way
758*77d1c127SSebastian Grimberg to resolve face orientation issues for 3D meshes (https://dl.acm.org/doi/pdf/10.1145/3524456). Will also be permuted and padded similarly to
759*77d1c127SSebastian Grimberg offsets.
760*77d1c127SSebastian Grimberg   @param[out] rstr         Address of the variable where the newly created CeedElemRestriction will be stored
761*77d1c127SSebastian Grimberg 
762*77d1c127SSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
763*77d1c127SSebastian Grimberg 
764*77d1c127SSebastian Grimberg   @ref Backend
765*77d1c127SSebastian Grimberg  **/
766*77d1c127SSebastian Grimberg int CeedElemRestrictionCreateBlockedCurlOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt blk_size, CeedInt num_comp,
767*77d1c127SSebastian Grimberg                                                  CeedInt comp_stride, CeedSize l_size, CeedMemType mem_type, CeedCopyMode copy_mode,
768*77d1c127SSebastian Grimberg                                                  const CeedInt *offsets, const CeedInt *curl_orients, CeedElemRestriction *rstr) {
769*77d1c127SSebastian Grimberg   CeedInt *blk_offsets;
770*77d1c127SSebastian Grimberg   CeedInt *blk_curl_orients;
771*77d1c127SSebastian Grimberg   CeedInt  num_blk = (num_elem / blk_size) + !!(num_elem % blk_size);
772*77d1c127SSebastian Grimberg 
773*77d1c127SSebastian Grimberg   if (!ceed->ElemRestrictionCreateBlockedCurlOriented) {
774*77d1c127SSebastian Grimberg     Ceed delegate;
775*77d1c127SSebastian Grimberg 
776*77d1c127SSebastian Grimberg     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"));
777*77d1c127SSebastian Grimberg     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreateBlockedCurlOriented");
778*77d1c127SSebastian Grimberg     CeedCall(CeedElemRestrictionCreateBlockedCurlOriented(delegate, num_elem, elem_size, blk_size, num_comp, comp_stride, l_size, mem_type, copy_mode,
779*77d1c127SSebastian Grimberg                                                           offsets, curl_orients, rstr));
780*77d1c127SSebastian Grimberg     return CEED_ERROR_SUCCESS;
781*77d1c127SSebastian Grimberg   }
782*77d1c127SSebastian Grimberg 
783*77d1c127SSebastian Grimberg   CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1");
784*77d1c127SSebastian Grimberg   CeedCheck(blk_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1");
785*77d1c127SSebastian Grimberg   CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component");
786*77d1c127SSebastian Grimberg   CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction component stride must be at least 1");
787*77d1c127SSebastian Grimberg 
788*77d1c127SSebastian Grimberg   CeedCall(CeedCalloc(1, rstr));
789*77d1c127SSebastian Grimberg 
790*77d1c127SSebastian Grimberg   CeedCall(CeedCalloc(num_blk * blk_size * elem_size, &blk_offsets));
791*77d1c127SSebastian Grimberg   CeedCall(CeedCalloc(num_blk * blk_size * 3 * elem_size, &blk_curl_orients));
792*77d1c127SSebastian Grimberg   CeedCall(CeedPermutePadOffsets(offsets, blk_offsets, num_blk, num_elem, blk_size, elem_size));
793*77d1c127SSebastian Grimberg   CeedCall(CeedPermutePadOffsets(curl_orients, blk_curl_orients, num_blk, num_elem, blk_size, 3 * elem_size));
794*77d1c127SSebastian Grimberg 
795*77d1c127SSebastian Grimberg   (*rstr)->ceed = ceed;
796*77d1c127SSebastian Grimberg   CeedCall(CeedReference(ceed));
797*77d1c127SSebastian Grimberg   (*rstr)->ref_count   = 1;
798*77d1c127SSebastian Grimberg   (*rstr)->num_elem    = num_elem;
799*77d1c127SSebastian Grimberg   (*rstr)->elem_size   = elem_size;
800*77d1c127SSebastian Grimberg   (*rstr)->num_comp    = num_comp;
801*77d1c127SSebastian Grimberg   (*rstr)->comp_stride = comp_stride;
802*77d1c127SSebastian Grimberg   (*rstr)->l_size      = l_size;
803*77d1c127SSebastian Grimberg   (*rstr)->num_blk     = num_blk;
804*77d1c127SSebastian Grimberg   (*rstr)->blk_size    = blk_size;
805*77d1c127SSebastian Grimberg   CeedCall(ceed->ElemRestrictionCreateBlockedCurlOriented(CEED_MEM_HOST, CEED_OWN_POINTER, (const CeedInt *)blk_offsets,
806*77d1c127SSebastian Grimberg                                                           (const CeedInt *)blk_curl_orients, *rstr));
807*77d1c127SSebastian Grimberg   if (copy_mode == CEED_OWN_POINTER) {
808*77d1c127SSebastian Grimberg     CeedCall(CeedFree(&offsets));
809*77d1c127SSebastian Grimberg   }
810*77d1c127SSebastian Grimberg   return CEED_ERROR_SUCCESS;
811*77d1c127SSebastian Grimberg }
812*77d1c127SSebastian Grimberg 
813*77d1c127SSebastian Grimberg /**
814*77d1c127SSebastian Grimberg   @brief Create a blocked strided CeedElemRestriction, typically only called by backends
8157509a596Sjeremylt 
816ea61e9acSJeremy L Thompson   @param[in]  ceed      Ceed object where the CeedElemRestriction will be created
817ea61e9acSJeremy L Thompson   @param[in]  num_elem  Number of elements described by the restriction
818ea61e9acSJeremy L Thompson   @param[in]  elem_size Size (number of "nodes") per element
819ea61e9acSJeremy L Thompson   @param[in]  blk_size  Number of elements in a block
820ea61e9acSJeremy L Thompson   @param[in]  num_comp  Number of field components per interpolation node (1 for scalar fields)
821*77d1c127SSebastian Grimberg   @param[in]  l_size    The size of the L-vector. This vector may be larger than the elements and fields given by this restriction.
822*77d1c127SSebastian Grimberg   @param[in]  strides   Array for strides between [nodes, components, elements]. Data for node i, component j, element k can be found in the L-vector
823*77d1c127SSebastian Grimberg at index i*strides[0] + j*strides[1] + k*strides[2]. @a CEED_STRIDES_BACKEND may be used with vectors created by a Ceed backend.
824ea61e9acSJeremy L Thompson   @param[out] rstr      Address of the variable where the newly created CeedElemRestriction will be stored
8257509a596Sjeremylt 
8267509a596Sjeremylt   @return An error code: 0 - success, otherwise - failure
8277509a596Sjeremylt 
8287a982d89SJeremy L. Thompson   @ref User
8297509a596Sjeremylt **/
8302b730f8bSJeremy L Thompson int CeedElemRestrictionCreateBlockedStrided(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt blk_size, CeedInt num_comp, CeedSize l_size,
8318621c6c6SJeremy L Thompson                                             const CeedInt strides[3], CeedElemRestriction *rstr) {
832d1d35e2fSjeremylt   CeedInt num_blk = (num_elem / blk_size) + !!(num_elem % blk_size);
8337509a596Sjeremylt 
8347509a596Sjeremylt   if (!ceed->ElemRestrictionCreateBlocked) {
8357509a596Sjeremylt     Ceed delegate;
8366574a04fSJeremy L Thompson 
8372b730f8bSJeremy L Thompson     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"));
8386402da51SJeremy L Thompson     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreateBlockedStrided");
8392b730f8bSJeremy L Thompson     CeedCall(CeedElemRestrictionCreateBlockedStrided(delegate, num_elem, elem_size, blk_size, num_comp, l_size, strides, rstr));
840e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
8417509a596Sjeremylt   }
8427509a596Sjeremylt 
8436574a04fSJeremy L Thompson   CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1");
8446574a04fSJeremy L Thompson   CeedCheck(blk_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1");
8456574a04fSJeremy L Thompson   CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component");
846e022e1f8SJeremy L Thompson 
8472b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, rstr));
848db002c03SJeremy L Thompson   CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed));
849d1d35e2fSjeremylt   (*rstr)->ref_count = 1;
850d1d35e2fSjeremylt   (*rstr)->num_elem  = num_elem;
851d1d35e2fSjeremylt   (*rstr)->elem_size = elem_size;
852d1d35e2fSjeremylt   (*rstr)->num_comp  = num_comp;
853d1d35e2fSjeremylt   (*rstr)->l_size    = l_size;
854d1d35e2fSjeremylt   (*rstr)->num_blk   = num_blk;
855d1d35e2fSjeremylt   (*rstr)->blk_size  = blk_size;
8562b730f8bSJeremy L Thompson   CeedCall(CeedMalloc(3, &(*rstr)->strides));
8572b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < 3; i++) (*rstr)->strides[i] = strides[i];
8582b730f8bSJeremy L Thompson   CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, NULL, *rstr));
859e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
8607509a596Sjeremylt }
8617509a596Sjeremylt 
8627509a596Sjeremylt /**
863c17ec2beSJeremy L Thompson   @brief Copy the pointer to a CeedElemRestriction and set `CeedElemRestrictionApply()` implementation to `CeedElemRestrictionApplyUnsigned()`.
864c17ec2beSJeremy L Thompson 
865c17ec2beSJeremy L Thompson   Both pointers should be destroyed with `CeedElemRestrictionDestroy()`.
866c17ec2beSJeremy L Thompson 
867c17ec2beSJeremy L Thompson   @param[in]     rstr          CeedElemRestriction to create unsigned reference to
868c17ec2beSJeremy L Thompson   @param[in,out] rstr_unsigned Variable to store unsigned CeedElemRestriction
869c17ec2beSJeremy L Thompson 
870c17ec2beSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
871c17ec2beSJeremy L Thompson 
872c17ec2beSJeremy L Thompson   @ref User
873c17ec2beSJeremy L Thompson **/
874c17ec2beSJeremy L Thompson int CeedElemRestrictionCreateUnsignedCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_unsigned) {
875c17ec2beSJeremy L Thompson   CeedCall(CeedCalloc(1, rstr_unsigned));
876c17ec2beSJeremy L Thompson 
877c17ec2beSJeremy L Thompson   // Copy old rstr
878c17ec2beSJeremy L Thompson   memcpy(*rstr_unsigned, rstr, sizeof(struct CeedElemRestriction_private));
879c17ec2beSJeremy L Thompson   (*rstr_unsigned)->ceed = NULL;
880c17ec2beSJeremy L Thompson   CeedCall(CeedReferenceCopy(rstr->ceed, &(*rstr_unsigned)->ceed));
881c17ec2beSJeremy L Thompson   (*rstr_unsigned)->ref_count = 1;
882c17ec2beSJeremy L Thompson   (*rstr_unsigned)->strides   = NULL;
883c17ec2beSJeremy L Thompson   if (rstr->strides) {
884c17ec2beSJeremy L Thompson     CeedCall(CeedMalloc(3, &(*rstr_unsigned)->strides));
885c17ec2beSJeremy L Thompson     for (CeedInt i = 0; i < 3; i++) (*rstr_unsigned)->strides[i] = rstr->strides[i];
886c17ec2beSJeremy L Thompson   }
887c17ec2beSJeremy L Thompson   CeedCall(CeedElemRestrictionReferenceCopy(rstr, &(*rstr_unsigned)->rstr_signed));
888c17ec2beSJeremy L Thompson 
889c17ec2beSJeremy L Thompson   // Override Apply
890c17ec2beSJeremy L Thompson   (*rstr_unsigned)->Apply = rstr->ApplyUnsigned;
891c17ec2beSJeremy L Thompson 
892c17ec2beSJeremy L Thompson   return CEED_ERROR_SUCCESS;
893c17ec2beSJeremy L Thompson }
894c17ec2beSJeremy L Thompson 
895c17ec2beSJeremy L Thompson /**
896ea61e9acSJeremy L Thompson   @brief Copy the pointer to a CeedElemRestriction.
8979fd66db6SSebastian Grimberg 
898ea61e9acSJeremy L Thompson   Both pointers should be destroyed with `CeedElemRestrictionDestroy()`.
8999560d06aSjeremylt 
9009fd66db6SSebastian Grimberg   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.
9019fd66db6SSebastian Grimberg         This CeedElemRestriction will be destroyed if `rstr_copy` is the only reference to this CeedElemRestriction.
902ea61e9acSJeremy L Thompson 
903ea61e9acSJeremy L Thompson   @param[in]     rstr      CeedElemRestriction to copy reference to
904ea61e9acSJeremy L Thompson   @param[in,out] rstr_copy Variable to store copied reference
9059560d06aSjeremylt 
9069560d06aSjeremylt   @return An error code: 0 - success, otherwise - failure
9079560d06aSjeremylt 
9089560d06aSjeremylt   @ref User
9099560d06aSjeremylt **/
9102b730f8bSJeremy L Thompson int CeedElemRestrictionReferenceCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_copy) {
911393ac2cdSJeremy L Thompson   if (rstr != CEED_ELEMRESTRICTION_NONE) CeedCall(CeedElemRestrictionReference(rstr));
9122b730f8bSJeremy L Thompson   CeedCall(CeedElemRestrictionDestroy(rstr_copy));
9139560d06aSjeremylt   *rstr_copy = rstr;
9149560d06aSjeremylt   return CEED_ERROR_SUCCESS;
9159560d06aSjeremylt }
9169560d06aSjeremylt 
9179560d06aSjeremylt /**
918b11c1e72Sjeremylt   @brief Create CeedVectors associated with a CeedElemRestriction
919b11c1e72Sjeremylt 
920ea61e9acSJeremy L Thompson   @param[in]  rstr  CeedElemRestriction
921ea61e9acSJeremy L Thompson   @param[out] l_vec The address of the L-vector to be created, or NULL
922ea61e9acSJeremy L Thompson   @param[out] e_vec The address of the E-vector to be created, or NULL
923b11c1e72Sjeremylt 
924b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
925dfdf5a53Sjeremylt 
9267a982d89SJeremy L. Thompson   @ref User
927b11c1e72Sjeremylt **/
9282b730f8bSJeremy L Thompson int CeedElemRestrictionCreateVector(CeedElemRestriction rstr, CeedVector *l_vec, CeedVector *e_vec) {
929d2643443SJeremy L Thompson   CeedSize e_size, l_size;
930d1d35e2fSjeremylt   l_size = rstr->l_size;
931d1d35e2fSjeremylt   e_size = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp;
9322b730f8bSJeremy L Thompson   if (l_vec) CeedCall(CeedVectorCreate(rstr->ceed, l_size, l_vec));
9332b730f8bSJeremy L Thompson   if (e_vec) CeedCall(CeedVectorCreate(rstr->ceed, e_size, e_vec));
934e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
935d7b241e6Sjeremylt }
936d7b241e6Sjeremylt 
937d7b241e6Sjeremylt /**
938d9e1f99aSValeria Barra   @brief Restrict an L-vector to an E-vector or apply its transpose
939d7b241e6Sjeremylt 
940ea61e9acSJeremy L Thompson   @param[in]  rstr    CeedElemRestriction
941ea61e9acSJeremy L Thompson   @param[in]  t_mode  Apply restriction or transpose
942ea61e9acSJeremy L Thompson   @param[in]  u       Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE)
943*77d1c127SSebastian Grimberg   @param[out] ru      Output vector (of shape [@a num_elem * @a elem_size] when t_mode=@ref CEED_NOTRANSPOSE). Ordering of the e-vector is decided by
944*77d1c127SSebastian Grimberg the backend.
945ea61e9acSJeremy L Thompson   @param[in]  request Request or @ref CEED_REQUEST_IMMEDIATE
946b11c1e72Sjeremylt 
947b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
948dfdf5a53Sjeremylt 
9497a982d89SJeremy L. Thompson   @ref User
950b11c1e72Sjeremylt **/
9512b730f8bSJeremy L Thompson int CeedElemRestrictionApply(CeedElemRestriction rstr, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, CeedRequest *request) {
952d7b241e6Sjeremylt   CeedInt m, n;
953d7b241e6Sjeremylt 
954d1d35e2fSjeremylt   if (t_mode == CEED_NOTRANSPOSE) {
955d1d35e2fSjeremylt     m = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp;
956d1d35e2fSjeremylt     n = rstr->l_size;
957d7b241e6Sjeremylt   } else {
958d1d35e2fSjeremylt     m = rstr->l_size;
959d1d35e2fSjeremylt     n = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp;
960d7b241e6Sjeremylt   }
9616574a04fSJeremy L Thompson   CeedCheck(n == u->length, rstr->ceed, CEED_ERROR_DIMENSION,
9626574a04fSJeremy L Thompson             "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", u->length, m, n);
9636574a04fSJeremy L Thompson   CeedCheck(m == ru->length, rstr->ceed, CEED_ERROR_DIMENSION,
9646574a04fSJeremy L Thompson             "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", ru->length, m, n);
9652b730f8bSJeremy L Thompson   if (rstr->num_elem > 0) CeedCall(rstr->Apply(rstr, t_mode, u, ru, request));
966e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
967d7b241e6Sjeremylt }
968d7b241e6Sjeremylt 
969d7b241e6Sjeremylt /**
970d9e1f99aSValeria Barra   @brief Restrict an L-vector to a block of an E-vector or apply its transpose
971be9261b7Sjeremylt 
972ea61e9acSJeremy L Thompson   @param[in]  rstr    CeedElemRestriction
973ea61e9acSJeremy L Thompson   @param[in]  block   Block number to restrict to/from, i.e. block=0 will handle elements [0 : blk_size] and block=3 will handle elements [3*blk_size
974ea61e9acSJeremy L Thompson : 4*blk_size]
975ea61e9acSJeremy L Thompson   @param[in]  t_mode  Apply restriction or transpose
976ea61e9acSJeremy L Thompson   @param[in]  u       Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE)
977*77d1c127SSebastian Grimberg   @param[out] ru      Output vector (of shape [@a blk_size * @a elem_size] when t_mode=@ref CEED_NOTRANSPOSE). Ordering of the e-vector is decided by
978*77d1c127SSebastian Grimberg the backend.
979ea61e9acSJeremy L Thompson   @param[in]  request Request or @ref CEED_REQUEST_IMMEDIATE
980be9261b7Sjeremylt 
981be9261b7Sjeremylt   @return An error code: 0 - success, otherwise - failure
982be9261b7Sjeremylt 
9837a982d89SJeremy L. Thompson   @ref Backend
984be9261b7Sjeremylt **/
9852b730f8bSJeremy L Thompson int CeedElemRestrictionApplyBlock(CeedElemRestriction rstr, CeedInt block, CeedTransposeMode t_mode, CeedVector u, CeedVector ru,
9862b730f8bSJeremy L Thompson                                   CeedRequest *request) {
987be9261b7Sjeremylt   CeedInt m, n;
988be9261b7Sjeremylt 
9896402da51SJeremy L Thompson   CeedCheck(rstr->ApplyBlock, rstr->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionApplyBlock");
9906402da51SJeremy L Thompson 
991d1d35e2fSjeremylt   if (t_mode == CEED_NOTRANSPOSE) {
992d1d35e2fSjeremylt     m = rstr->blk_size * rstr->elem_size * rstr->num_comp;
993d1d35e2fSjeremylt     n = rstr->l_size;
994be9261b7Sjeremylt   } else {
995d1d35e2fSjeremylt     m = rstr->l_size;
996d1d35e2fSjeremylt     n = rstr->blk_size * rstr->elem_size * rstr->num_comp;
997be9261b7Sjeremylt   }
9986574a04fSJeremy L Thompson   CeedCheck(n == u->length, rstr->ceed, CEED_ERROR_DIMENSION,
9996574a04fSJeremy L Thompson             "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", u->length, m, n);
10006574a04fSJeremy L Thompson   CeedCheck(m == ru->length, rstr->ceed, CEED_ERROR_DIMENSION,
10016574a04fSJeremy L Thompson             "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", ru->length, m, n);
10026574a04fSJeremy L Thompson   CeedCheck(rstr->blk_size * block <= rstr->num_elem, rstr->ceed, CEED_ERROR_DIMENSION,
10036574a04fSJeremy L Thompson             "Cannot retrieve block %" CeedInt_FMT ", element %" CeedInt_FMT " > total elements %" CeedInt_FMT "", block, rstr->blk_size * block,
10046574a04fSJeremy L Thompson             rstr->num_elem);
10052b730f8bSJeremy L Thompson   CeedCall(rstr->ApplyBlock(rstr, block, t_mode, u, ru, request));
1006e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1007be9261b7Sjeremylt }
1008be9261b7Sjeremylt 
1009be9261b7Sjeremylt /**
1010b7c9bbdaSJeremy L Thompson   @brief Get the Ceed associated with a CeedElemRestriction
1011b7c9bbdaSJeremy L Thompson 
1012ea61e9acSJeremy L Thompson   @param[in]  rstr CeedElemRestriction
1013b7c9bbdaSJeremy L Thompson   @param[out] ceed Variable to store Ceed
1014b7c9bbdaSJeremy L Thompson 
1015b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1016b7c9bbdaSJeremy L Thompson 
1017b7c9bbdaSJeremy L Thompson   @ref Advanced
1018b7c9bbdaSJeremy L Thompson **/
1019b7c9bbdaSJeremy L Thompson int CeedElemRestrictionGetCeed(CeedElemRestriction rstr, Ceed *ceed) {
1020b7c9bbdaSJeremy L Thompson   *ceed = rstr->ceed;
1021b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1022b7c9bbdaSJeremy L Thompson }
1023b7c9bbdaSJeremy L Thompson 
1024b7c9bbdaSJeremy L Thompson /**
1025d979a051Sjeremylt   @brief Get the L-vector component stride
1026a681ae63Sjeremylt 
1027ea61e9acSJeremy L Thompson   @param[in]  rstr        CeedElemRestriction
1028d1d35e2fSjeremylt   @param[out] comp_stride Variable to store component stride
1029a681ae63Sjeremylt 
1030a681ae63Sjeremylt   @return An error code: 0 - success, otherwise - failure
1031a681ae63Sjeremylt 
1032b7c9bbdaSJeremy L Thompson   @ref Advanced
1033a681ae63Sjeremylt **/
10342b730f8bSJeremy L Thompson int CeedElemRestrictionGetCompStride(CeedElemRestriction rstr, CeedInt *comp_stride) {
1035d1d35e2fSjeremylt   *comp_stride = rstr->comp_stride;
1036e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1037a681ae63Sjeremylt }
1038a681ae63Sjeremylt 
1039a681ae63Sjeremylt /**
1040a681ae63Sjeremylt   @brief Get the total number of elements in the range of a CeedElemRestriction
1041a681ae63Sjeremylt 
1042ea61e9acSJeremy L Thompson   @param[in] rstr      CeedElemRestriction
1043d1d35e2fSjeremylt   @param[out] num_elem Variable to store number of elements
1044a681ae63Sjeremylt 
1045a681ae63Sjeremylt   @return An error code: 0 - success, otherwise - failure
1046a681ae63Sjeremylt 
1047b7c9bbdaSJeremy L Thompson   @ref Advanced
1048a681ae63Sjeremylt **/
10492b730f8bSJeremy L Thompson int CeedElemRestrictionGetNumElements(CeedElemRestriction rstr, CeedInt *num_elem) {
1050d1d35e2fSjeremylt   *num_elem = rstr->num_elem;
1051e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1052a681ae63Sjeremylt }
1053a681ae63Sjeremylt 
1054a681ae63Sjeremylt /**
1055a681ae63Sjeremylt   @brief Get the size of elements in the CeedElemRestriction
1056a681ae63Sjeremylt 
1057ea61e9acSJeremy L Thompson   @param[in]  rstr      CeedElemRestriction
1058d1d35e2fSjeremylt   @param[out] elem_size Variable to store size of elements
1059a681ae63Sjeremylt 
1060a681ae63Sjeremylt   @return An error code: 0 - success, otherwise - failure
1061a681ae63Sjeremylt 
1062b7c9bbdaSJeremy L Thompson   @ref Advanced
1063a681ae63Sjeremylt **/
10642b730f8bSJeremy L Thompson int CeedElemRestrictionGetElementSize(CeedElemRestriction rstr, CeedInt *elem_size) {
1065d1d35e2fSjeremylt   *elem_size = rstr->elem_size;
1066e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1067a681ae63Sjeremylt }
1068a681ae63Sjeremylt 
1069a681ae63Sjeremylt /**
1070d979a051Sjeremylt   @brief Get the size of the l-vector for a CeedElemRestriction
1071a681ae63Sjeremylt 
1072ea61e9acSJeremy L Thompson   @param[in]  rstr   CeedElemRestriction
1073d1d35e2fSjeremylt   @param[out] l_size Variable to store number of nodes
1074a681ae63Sjeremylt 
1075a681ae63Sjeremylt   @return An error code: 0 - success, otherwise - failure
1076a681ae63Sjeremylt 
1077b7c9bbdaSJeremy L Thompson   @ref Advanced
1078a681ae63Sjeremylt **/
10792b730f8bSJeremy L Thompson int CeedElemRestrictionGetLVectorSize(CeedElemRestriction rstr, CeedSize *l_size) {
1080d1d35e2fSjeremylt   *l_size = rstr->l_size;
1081e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1082a681ae63Sjeremylt }
1083a681ae63Sjeremylt 
1084a681ae63Sjeremylt /**
1085ea61e9acSJeremy L Thompson   @brief Get the number of components in the elements of a CeedElemRestriction
1086a681ae63Sjeremylt 
1087ea61e9acSJeremy L Thompson   @param[in]  rstr     CeedElemRestriction
1088d1d35e2fSjeremylt   @param[out] num_comp Variable to store number of components
1089a681ae63Sjeremylt 
1090a681ae63Sjeremylt   @return An error code: 0 - success, otherwise - failure
1091a681ae63Sjeremylt 
1092b7c9bbdaSJeremy L Thompson   @ref Advanced
1093a681ae63Sjeremylt **/
10942b730f8bSJeremy L Thompson int CeedElemRestrictionGetNumComponents(CeedElemRestriction rstr, CeedInt *num_comp) {
1095d1d35e2fSjeremylt   *num_comp = rstr->num_comp;
1096e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1097a681ae63Sjeremylt }
1098a681ae63Sjeremylt 
1099a681ae63Sjeremylt /**
1100a681ae63Sjeremylt   @brief Get the number of blocks in a CeedElemRestriction
1101a681ae63Sjeremylt 
1102ea61e9acSJeremy L Thompson   @param[in]  rstr      CeedElemRestriction
1103d1d35e2fSjeremylt   @param[out] num_block Variable to store number of blocks
1104a681ae63Sjeremylt 
1105a681ae63Sjeremylt   @return An error code: 0 - success, otherwise - failure
1106a681ae63Sjeremylt 
1107b7c9bbdaSJeremy L Thompson   @ref Advanced
1108a681ae63Sjeremylt **/
11092b730f8bSJeremy L Thompson int CeedElemRestrictionGetNumBlocks(CeedElemRestriction rstr, CeedInt *num_block) {
1110d1d35e2fSjeremylt   *num_block = rstr->num_blk;
1111e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1112a681ae63Sjeremylt }
1113a681ae63Sjeremylt 
1114a681ae63Sjeremylt /**
1115a681ae63Sjeremylt   @brief Get the size of blocks in the CeedElemRestriction
1116a681ae63Sjeremylt 
1117ea61e9acSJeremy L Thompson   @param[in]  rstr     CeedElemRestriction
1118d1d35e2fSjeremylt   @param[out] blk_size Variable to store size of blocks
1119a681ae63Sjeremylt 
1120a681ae63Sjeremylt   @return An error code: 0 - success, otherwise - failure
1121a681ae63Sjeremylt 
1122b7c9bbdaSJeremy L Thompson   @ref Advanced
1123a681ae63Sjeremylt **/
11242b730f8bSJeremy L Thompson int CeedElemRestrictionGetBlockSize(CeedElemRestriction rstr, CeedInt *blk_size) {
1125d1d35e2fSjeremylt   *blk_size = rstr->blk_size;
1126e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1127a681ae63Sjeremylt }
1128a681ae63Sjeremylt 
1129a681ae63Sjeremylt /**
1130d9e1f99aSValeria Barra   @brief Get the multiplicity of nodes in a CeedElemRestriction
11311469ee4dSjeremylt 
1132ea61e9acSJeremy L Thompson   @param[in]  rstr CeedElemRestriction
1133d1d35e2fSjeremylt   @param[out] mult Vector to store multiplicity (of size l_size)
11341469ee4dSjeremylt 
11351469ee4dSjeremylt   @return An error code: 0 - success, otherwise - failure
11361469ee4dSjeremylt 
11377a982d89SJeremy L. Thompson   @ref User
11381469ee4dSjeremylt **/
11392b730f8bSJeremy L Thompson int CeedElemRestrictionGetMultiplicity(CeedElemRestriction rstr, CeedVector mult) {
1140d1d35e2fSjeremylt   CeedVector e_vec;
11411469ee4dSjeremylt 
114225509ebbSRezgar Shakeri   // Create e_vec to hold intermediate computation in E^T (E 1)
11432b730f8bSJeremy L Thompson   CeedCall(CeedElemRestrictionCreateVector(rstr, NULL, &e_vec));
11441469ee4dSjeremylt 
114525509ebbSRezgar Shakeri   // Compute e_vec = E * 1
11462b730f8bSJeremy L Thompson   CeedCall(CeedVectorSetValue(mult, 1.0));
11472b730f8bSJeremy L Thompson   CeedCall(CeedElemRestrictionApply(rstr, CEED_NOTRANSPOSE, mult, e_vec, CEED_REQUEST_IMMEDIATE));
114825509ebbSRezgar Shakeri   // Compute multiplicity, mult = E^T * e_vec = E^T (E 1)
11492b730f8bSJeremy L Thompson   CeedCall(CeedVectorSetValue(mult, 0.0));
11502b730f8bSJeremy L Thompson   CeedCall(CeedElemRestrictionApply(rstr, CEED_TRANSPOSE, e_vec, mult, CEED_REQUEST_IMMEDIATE));
11511469ee4dSjeremylt   // Cleanup
11522b730f8bSJeremy L Thompson   CeedCall(CeedVectorDestroy(&e_vec));
1153e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
11541469ee4dSjeremylt }
11551469ee4dSjeremylt 
11561469ee4dSjeremylt /**
1157f02ca4a2SJed Brown   @brief View a CeedElemRestriction
1158f02ca4a2SJed Brown 
1159f02ca4a2SJed Brown   @param[in] rstr   CeedElemRestriction to view
1160f02ca4a2SJed Brown   @param[in] stream Stream to write; typically stdout/stderr or a file
1161f02ca4a2SJed Brown 
1162f02ca4a2SJed Brown   @return Error code: 0 - success, otherwise - failure
1163f02ca4a2SJed Brown 
11647a982d89SJeremy L. Thompson   @ref User
1165f02ca4a2SJed Brown **/
1166f02ca4a2SJed Brown int CeedElemRestrictionView(CeedElemRestriction rstr, FILE *stream) {
11677509a596Sjeremylt   char stridesstr[500];
11682b730f8bSJeremy L Thompson   if (rstr->strides) {
11692b730f8bSJeremy L Thompson     sprintf(stridesstr, "[%" CeedInt_FMT ", %" CeedInt_FMT ", %" CeedInt_FMT "]", rstr->strides[0], rstr->strides[1], rstr->strides[2]);
11702b730f8bSJeremy L Thompson   } else {
1171990fdeb6SJeremy L Thompson     sprintf(stridesstr, "%" CeedInt_FMT, rstr->comp_stride);
11722b730f8bSJeremy L Thompson   }
11737509a596Sjeremylt 
11742b730f8bSJeremy L Thompson   fprintf(stream, "%sCeedElemRestriction from (%td, %" CeedInt_FMT ") to %" CeedInt_FMT " elements with %" CeedInt_FMT " nodes each and %s %s\n",
11752b730f8bSJeremy L Thompson           rstr->blk_size > 1 ? "Blocked " : "", rstr->l_size, rstr->num_comp, rstr->num_elem, rstr->elem_size,
1176d979a051Sjeremylt           rstr->strides ? "strides" : "component stride", stridesstr);
1177e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1178f02ca4a2SJed Brown }
1179f02ca4a2SJed Brown 
1180f02ca4a2SJed Brown /**
1181b11c1e72Sjeremylt   @brief Destroy a CeedElemRestriction
1182b11c1e72Sjeremylt 
1183ea61e9acSJeremy L Thompson   @param[in,out] rstr CeedElemRestriction to destroy
1184b11c1e72Sjeremylt 
1185b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1186dfdf5a53Sjeremylt 
11877a982d89SJeremy L. Thompson   @ref User
1188b11c1e72Sjeremylt **/
11894ce2993fSjeremylt int CeedElemRestrictionDestroy(CeedElemRestriction *rstr) {
1190393ac2cdSJeremy L Thompson   if (!*rstr || *rstr == CEED_ELEMRESTRICTION_NONE || --(*rstr)->ref_count > 0) {
1191ad6481ceSJeremy L Thompson     *rstr = NULL;
1192ad6481ceSJeremy L Thompson     return CEED_ERROR_SUCCESS;
1193ad6481ceSJeremy L Thompson   }
11946574a04fSJeremy L Thompson   CeedCheck((*rstr)->num_readers == 0, (*rstr)->ceed, CEED_ERROR_ACCESS,
11956574a04fSJeremy L Thompson             "Cannot destroy CeedElemRestriction, a process has read access to the offset data");
1196c17ec2beSJeremy L Thompson 
1197c17ec2beSJeremy L Thompson   // Only destroy backend data once between rstr and unsigned copy
1198c17ec2beSJeremy L Thompson   if ((*rstr)->rstr_signed) CeedCall(CeedElemRestrictionDestroy(&(*rstr)->rstr_signed));
1199c17ec2beSJeremy L Thompson   else if ((*rstr)->Destroy) CeedCall((*rstr)->Destroy(*rstr));
1200c17ec2beSJeremy L Thompson 
12012b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*rstr)->strides));
12022b730f8bSJeremy L Thompson   CeedCall(CeedDestroy(&(*rstr)->ceed));
12032b730f8bSJeremy L Thompson   CeedCall(CeedFree(rstr));
1204e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1205d7b241e6Sjeremylt }
1206d7b241e6Sjeremylt 
1207d7b241e6Sjeremylt /// @}
1208