xref: /libCEED/interface/ceed-elemrestriction.c (revision b11824b355ec5db8d1d0662d2c2bd260606aac4b)
1 // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors.
2 // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
3 //
4 // SPDX-License-Identifier: BSD-2-Clause
5 //
6 // This file is part of CEED:  http://github.com/ceed
7 
8 #include <ceed/ceed.h>
9 #include <ceed/backend.h>
10 #include <ceed-impl.h>
11 #include <stdbool.h>
12 #include <stdio.h>
13 
14 /// @file
15 /// Implementation of CeedElemRestriction interfaces
16 
17 /// ----------------------------------------------------------------------------
18 /// CeedElemRestriction Library Internal Functions
19 /// ----------------------------------------------------------------------------
20 /// @addtogroup CeedElemRestrictionDeveloper
21 /// @{
22 
23 /**
24   @brief Permute and pad offsets for a blocked restriction
25 
26   @param offsets     Array of shape [@a num_elem, @a elem_size]. Row i holds the
27                        ordered list of the offsets (into the input CeedVector)
28                        for the unknowns corresponding to element i, where
29                        0 <= i < @a num_elem. All offsets must be in the range
30                        [0, @a l_size - 1].
31   @param blk_offsets Array of permuted and padded offsets of
32                        shape [@a num_blk, @a elem_size, @a blk_size].
33   @param num_blk     Number of blocks
34   @param num_elem    Number of elements
35   @param blk_size    Number of elements in a block
36   @param elem_size   Size of each element
37 
38   @return An error code: 0 - success, otherwise - failure
39 
40   @ref Utility
41 **/
42 int CeedPermutePadOffsets(const CeedInt *offsets, CeedInt *blk_offsets,
43                           CeedInt num_blk, CeedInt num_elem, CeedInt blk_size,
44                           CeedInt elem_size) {
45   for (CeedInt e=0; e<num_blk*blk_size; e+=blk_size)
46     for (int j=0; j<blk_size; j++)
47       for (int k=0; k<elem_size; k++)
48         blk_offsets[e*elem_size + k*blk_size + j]
49           = offsets[CeedIntMin(e+j,num_elem-1)*elem_size + k];
50   return CEED_ERROR_SUCCESS;
51 }
52 
53 /// @}
54 
55 /// ----------------------------------------------------------------------------
56 /// CeedElemRestriction Backend API
57 /// ----------------------------------------------------------------------------
58 /// @addtogroup CeedElemRestrictionBackend
59 /// @{
60 
61 /**
62 
63   @brief Get the strides of a strided CeedElemRestriction
64 
65   @param rstr          CeedElemRestriction
66   @param[out] strides  Variable to store strides array
67 
68   @return An error code: 0 - success, otherwise - failure
69 
70   @ref Backend
71 **/
72 int CeedElemRestrictionGetStrides(CeedElemRestriction rstr,
73                                   CeedInt (*strides)[3]) {
74   if (!rstr->strides)
75     // LCOV_EXCL_START
76     return CeedError(rstr->ceed, CEED_ERROR_MINOR,
77                      "ElemRestriction has no stride data");
78   // LCOV_EXCL_STOP
79 
80   for (int i=0; i<3; i++)
81     (*strides)[i] = rstr->strides[i];
82   return CEED_ERROR_SUCCESS;
83 }
84 
85 /**
86   @brief Get read-only access to a CeedElemRestriction offsets array by memtype
87 
88   @param rstr          CeedElemRestriction to retrieve offsets
89   @param mem_type      Memory type on which to access the array.  If the backend
90                          uses a different memory type, this will perform a copy
91                          (possibly cached).
92   @param[out] offsets  Array on memory type mem_type
93 
94   @return An error code: 0 - success, otherwise - failure
95 
96   @ref User
97 **/
98 int CeedElemRestrictionGetOffsets(CeedElemRestriction rstr,
99                                   CeedMemType mem_type,
100                                   const CeedInt **offsets) {
101   int ierr;
102 
103   if (!rstr->GetOffsets)
104     // LCOV_EXCL_START
105     return CeedError(rstr->ceed, CEED_ERROR_UNSUPPORTED,
106                      "Backend does not support GetOffsets");
107   // LCOV_EXCL_STOP
108 
109   ierr = rstr->GetOffsets(rstr, mem_type, offsets); CeedChk(ierr);
110   rstr->num_readers++;
111   return CEED_ERROR_SUCCESS;
112 }
113 
114 /**
115   @brief Restore an offsets array obtained using CeedElemRestrictionGetOffsets()
116 
117   @param rstr     CeedElemRestriction to restore
118   @param offsets  Array of offset data
119 
120   @return An error code: 0 - success, otherwise - failure
121 
122   @ref User
123 **/
124 int CeedElemRestrictionRestoreOffsets(CeedElemRestriction rstr,
125                                       const CeedInt **offsets) {
126   *offsets = NULL;
127   rstr->num_readers--;
128   return CEED_ERROR_SUCCESS;
129 }
130 
131 /**
132   @brief Get the strided status of a CeedElemRestriction
133 
134   @param rstr             CeedElemRestriction
135   @param[out] is_strided  Variable to store strided status, 1 if strided else 0
136 
137   @return An error code: 0 - success, otherwise - failure
138 
139   @ref Backend
140 **/
141 int CeedElemRestrictionIsStrided(CeedElemRestriction rstr, bool *is_strided) {
142   *is_strided = rstr->strides ? true : false;
143   return CEED_ERROR_SUCCESS;
144 }
145 
146 /**
147   @brief Get oriented status of a CeedElemRestriction
148 
149   @param rstr             CeedElemRestriction
150   @param[out] is_oriented  Variable to store oriented status, 1 if oriented else 0
151 
152   @return An error code: 0 - success, otherwise - failure
153 
154   @ref Backend
155 **/
156 int CeedElemRestrictionIsOriented(CeedElemRestriction rstr, bool *is_oriented) {
157   *is_oriented = rstr->is_oriented;
158   return CEED_ERROR_SUCCESS;
159 }
160 
161 /**
162   @brief Get the backend stride status of a CeedElemRestriction
163 
164   @param rstr                      CeedElemRestriction
165   @param[out] has_backend_strides  Variable to store stride status
166 
167   @return An error code: 0 - success, otherwise - failure
168 
169   @ref Backend
170 **/
171 int CeedElemRestrictionHasBackendStrides(CeedElemRestriction rstr,
172     bool *has_backend_strides) {
173   if (!rstr->strides)
174     // LCOV_EXCL_START
175     return CeedError(rstr->ceed, CEED_ERROR_MINOR,
176                      "ElemRestriction has no stride data");
177   // LCOV_EXCL_STOP
178 
179   *has_backend_strides = ((rstr->strides[0] == CEED_STRIDES_BACKEND[0]) &&
180                           (rstr->strides[1] == CEED_STRIDES_BACKEND[1]) &&
181                           (rstr->strides[2] == CEED_STRIDES_BACKEND[2]));
182   return CEED_ERROR_SUCCESS;
183 }
184 
185 /**
186 
187   @brief Get the E-vector layout of a CeedElemRestriction
188 
189   @param rstr         CeedElemRestriction
190   @param[out] layout  Variable to store layout array,
191                         stored as [nodes, components, elements].
192                         The data for node i, component j, element k in the
193                         E-vector is given by
194                         i*layout[0] + j*layout[1] + k*layout[2]
195 
196   @return An error code: 0 - success, otherwise - failure
197 
198   @ref Backend
199 **/
200 int CeedElemRestrictionGetELayout(CeedElemRestriction rstr,
201                                   CeedInt (*layout)[3]) {
202   if (!rstr->layout[0])
203     // LCOV_EXCL_START
204     return CeedError(rstr->ceed, CEED_ERROR_MINOR,
205                      "ElemRestriction has no layout data");
206   // LCOV_EXCL_STOP
207 
208   for (int i=0; i<3; i++)
209     (*layout)[i] = rstr->layout[i];
210   return CEED_ERROR_SUCCESS;
211 }
212 
213 /**
214 
215   @brief Set the E-vector layout of a CeedElemRestriction
216 
217   @param rstr    CeedElemRestriction
218   @param layout  Variable to containing layout array,
219                    stored as [nodes, components, elements].
220                    The data for node i, component j, element k in the
221                    E-vector is given by
222                    i*layout[0] + j*layout[1] + k*layout[2]
223 
224   @return An error code: 0 - success, otherwise - failure
225 
226   @ref Backend
227 **/
228 int CeedElemRestrictionSetELayout(CeedElemRestriction rstr,
229                                   CeedInt layout[3]) {
230   for (int i = 0; i<3; i++)
231     rstr->layout[i] = layout[i];
232   return CEED_ERROR_SUCCESS;
233 }
234 
235 /**
236   @brief Get the backend data of a CeedElemRestriction
237 
238   @param rstr       CeedElemRestriction
239   @param[out] data  Variable to store data
240 
241   @return An error code: 0 - success, otherwise - failure
242 
243   @ref Backend
244 **/
245 int CeedElemRestrictionGetData(CeedElemRestriction rstr, void *data) {
246   *(void **)data = rstr->data;
247   return CEED_ERROR_SUCCESS;
248 }
249 
250 /**
251   @brief Set the backend data of a CeedElemRestriction
252 
253   @param[out] rstr  CeedElemRestriction
254   @param data       Data to set
255 
256   @return An error code: 0 - success, otherwise - failure
257 
258   @ref Backend
259 **/
260 int CeedElemRestrictionSetData(CeedElemRestriction rstr, void *data) {
261   rstr->data = data;
262   return CEED_ERROR_SUCCESS;
263 }
264 
265 /**
266   @brief Increment the reference counter for a CeedElemRestriction
267 
268   @param rstr  ElemRestriction to increment the reference counter
269 
270   @return An error code: 0 - success, otherwise - failure
271 
272   @ref Backend
273 **/
274 int CeedElemRestrictionReference(CeedElemRestriction rstr) {
275   rstr->ref_count++;
276   return CEED_ERROR_SUCCESS;
277 }
278 
279 /// @}
280 
281 /// @cond DOXYGEN_SKIP
282 static struct CeedElemRestriction_private ceed_elemrestriction_none;
283 /// @endcond
284 
285 /// ----------------------------------------------------------------------------
286 /// CeedElemRestriction Public API
287 /// ----------------------------------------------------------------------------
288 /// @addtogroup CeedElemRestrictionUser
289 /// @{
290 
291 /// Indicate that the stride is determined by the backend
292 const CeedInt CEED_STRIDES_BACKEND[3] = {0};
293 
294 /// Indicate that no CeedElemRestriction is provided by the user
295 const CeedElemRestriction CEED_ELEMRESTRICTION_NONE =
296   &ceed_elemrestriction_none;
297 
298 /**
299   @brief Create a CeedElemRestriction
300 
301   @param ceed         A Ceed object where the CeedElemRestriction will be created
302   @param num_elem     Number of elements described in the @a offsets array
303   @param elem_size    Size (number of "nodes") per element
304   @param num_comp     Number of field components per interpolation node
305                         (1 for scalar fields)
306   @param comp_stride  Stride between components for the same L-vector "node".
307                         Data for node i, component j, element k can be found in
308                         the L-vector at index
309                         offsets[i + k*elem_size] + j*comp_stride.
310   @param l_size       The size of the L-vector. This vector may be larger than
311                         the elements and fields given by this restriction.
312   @param mem_type     Memory type of the @a offsets array, see CeedMemType
313   @param copy_mode    Copy mode for the @a offsets array, see CeedCopyMode
314   @param offsets      Array of shape [@a num_elem, @a elem_size]. Row i holds the
315                         ordered list of the offsets (into the input CeedVector)
316                         for the unknowns corresponding to element i, where
317                         0 <= i < @a num_elem. All offsets must be in the range
318                         [0, @a l_size - 1].
319   @param[out] rstr    Address of the variable where the newly created
320                         CeedElemRestriction will be stored
321 
322   @return An error code: 0 - success, otherwise - failure
323 
324   @ref User
325 **/
326 int CeedElemRestrictionCreate(Ceed ceed, CeedInt num_elem, CeedInt elem_size,
327                               CeedInt num_comp, CeedInt comp_stride,
328                               CeedSize l_size, CeedMemType mem_type,
329                               CeedCopyMode copy_mode, const CeedInt *offsets,
330                               CeedElemRestriction *rstr) {
331   int ierr;
332 
333   if (!ceed->ElemRestrictionCreate) {
334     Ceed delegate;
335     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
336     CeedChk(ierr);
337 
338     if (!delegate)
339       // LCOV_EXCL_START
340       return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
341                        "Backend does not support ElemRestrictionCreate");
342     // LCOV_EXCL_STOP
343 
344     ierr = CeedElemRestrictionCreate(delegate, num_elem, elem_size, num_comp,
345                                      comp_stride, l_size, mem_type, copy_mode,
346                                      offsets, rstr); CeedChk(ierr);
347     return CEED_ERROR_SUCCESS;
348   }
349 
350   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
351   (*rstr)->ceed = ceed;
352   ierr = CeedReference(ceed); CeedChk(ierr);
353   (*rstr)->ref_count = 1;
354   (*rstr)->num_elem = num_elem;
355   (*rstr)->elem_size = elem_size;
356   (*rstr)->num_comp = num_comp;
357   (*rstr)->comp_stride = comp_stride;
358   (*rstr)->l_size = l_size;
359   (*rstr)->num_blk = num_elem;
360   (*rstr)->blk_size = 1;
361   (*rstr)->is_oriented = 0;
362   ierr = ceed->ElemRestrictionCreate(mem_type, copy_mode, offsets, *rstr);
363   CeedChk(ierr);
364   return CEED_ERROR_SUCCESS;
365 }
366 
367 /**
368   @brief Create a CeedElemRestriction with orientation sign
369 
370   @param ceed         A Ceed object where the CeedElemRestriction will be created
371   @param num_elem     Number of elements described in the @a offsets array
372   @param elem_size    Size (number of "nodes") per element
373   @param num_comp     Number of field components per interpolation node
374                         (1 for scalar fields)
375   @param comp_stride  Stride between components for the same L-vector "node".
376                         Data for node i, component j, element k can be found in
377                         the L-vector at index
378                         offsets[i + k*elem_size] + j*comp_stride.
379   @param l_size       The size of the L-vector. This vector may be larger than
380                         the elements and fields given by this restriction.
381   @param mem_type     Memory type of the @a offsets array, see CeedMemType
382   @param copy_mode    Copy mode for the @a offsets array, see CeedCopyMode
383   @param offsets      Array of shape [@a num_elem, @a elem_size]. Row i holds the
384                         ordered list of the offsets (into the input CeedVector)
385                         for the unknowns corresponding to element i, where
386                         0 <= i < @a num_elem. All offsets must be in the range
387                         [0, @a l_size - 1].
388   @param orient       Array of shape [@a num_elem, @a elem_size] with bool false
389                         for positively oriented and true to flip the orientation.
390   @param[out] rstr    Address of the variable where the newly created
391                         CeedElemRestriction will be stored
392 
393   @return An error code: 0 - success, otherwise - failure
394 
395   @ref User
396 **/
397 int CeedElemRestrictionCreateOriented(Ceed ceed, CeedInt num_elem,
398                                       CeedInt elem_size, CeedInt num_comp,
399                                       CeedInt comp_stride, CeedSize l_size,
400                                       CeedMemType mem_type, CeedCopyMode copy_mode,
401                                       const CeedInt *offsets, const bool *orient,
402                                       CeedElemRestriction *rstr) {
403   int ierr;
404 
405   if (!ceed->ElemRestrictionCreateOriented) {
406     Ceed delegate;
407     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
408     CeedChk(ierr);
409 
410     if (!delegate)
411       // LCOV_EXCL_START
412       return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
413                        "Backend does not implement ElemRestrictionCreateOriented");
414     // LCOV_EXCL_STOP
415 
416     ierr = CeedElemRestrictionCreateOriented(delegate, num_elem, elem_size,
417            num_comp, comp_stride, l_size, mem_type, copy_mode, offsets,
418            orient, rstr); CeedChk(ierr);
419     return CEED_ERROR_SUCCESS;
420   }
421 
422   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
423   (*rstr)->ceed = ceed;
424   ierr = CeedReference(ceed); CeedChk(ierr);
425   (*rstr)->ref_count = 1;
426   (*rstr)->num_elem = num_elem;
427   (*rstr)->elem_size = elem_size;
428   (*rstr)->num_comp = num_comp;
429   (*rstr)->comp_stride = comp_stride;
430   (*rstr)->l_size = l_size;
431   (*rstr)->num_blk = num_elem;
432   (*rstr)->blk_size = 1;
433   (*rstr)->is_oriented = 1;
434   ierr = ceed->ElemRestrictionCreateOriented(mem_type, copy_mode,
435          offsets, orient, *rstr); CeedChk(ierr);
436   return CEED_ERROR_SUCCESS;
437 }
438 
439 /**
440   @brief Create a strided CeedElemRestriction
441 
442   @param ceed       A Ceed object where the CeedElemRestriction will be created
443   @param num_elem   Number of elements described by the restriction
444   @param elem_size  Size (number of "nodes") per element
445   @param num_comp   Number of field components per interpolation "node"
446                       (1 for scalar fields)
447   @param l_size     The size of the L-vector. This vector may be larger than
448                       the elements and fields given by this restriction.
449   @param strides    Array for strides between [nodes, components, elements].
450                       Data for node i, component j, element k can be found in
451                       the L-vector at index
452                       i*strides[0] + j*strides[1] + k*strides[2].
453                       @a CEED_STRIDES_BACKEND may be used with vectors created
454                       by a Ceed backend.
455   @param rstr       Address of the variable where the newly created
456                       CeedElemRestriction will be stored
457 
458   @return An error code: 0 - success, otherwise - failure
459 
460   @ref User
461 **/
462 int CeedElemRestrictionCreateStrided(Ceed ceed, CeedInt num_elem,
463                                      CeedInt elem_size,
464                                      CeedInt num_comp, CeedSize l_size,
465                                      const CeedInt strides[3],
466                                      CeedElemRestriction *rstr) {
467   int ierr;
468 
469   if (!ceed->ElemRestrictionCreate) {
470     Ceed delegate;
471     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
472     CeedChk(ierr);
473 
474     if (!delegate)
475       // LCOV_EXCL_START
476       return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
477                        "Backend does not support ElemRestrictionCreate");
478     // LCOV_EXCL_STOP
479 
480     ierr = CeedElemRestrictionCreateStrided(delegate, num_elem, elem_size, num_comp,
481                                             l_size, strides, rstr);
482     CeedChk(ierr);
483     return CEED_ERROR_SUCCESS;
484   }
485 
486   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
487   (*rstr)->ceed = ceed;
488   ierr = CeedReference(ceed); CeedChk(ierr);
489   (*rstr)->ref_count = 1;
490   (*rstr)->num_elem = num_elem;
491   (*rstr)->elem_size = elem_size;
492   (*rstr)->num_comp = num_comp;
493   (*rstr)->l_size = l_size;
494   (*rstr)->num_blk = num_elem;
495   (*rstr)->blk_size = 1;
496   (*rstr)->is_oriented = 0;
497   ierr = CeedMalloc(3, &(*rstr)->strides); CeedChk(ierr);
498   for (int i=0; i<3; i++)
499     (*rstr)->strides[i] = strides[i];
500   ierr = ceed->ElemRestrictionCreate(CEED_MEM_HOST, CEED_OWN_POINTER, NULL,
501                                      *rstr);
502   CeedChk(ierr);
503   return CEED_ERROR_SUCCESS;
504 }
505 
506 /**
507   @brief Create a blocked CeedElemRestriction, typically only called by backends
508 
509   @param ceed         A Ceed object where the CeedElemRestriction will be created.
510   @param num_elem     Number of elements described in the @a offsets array.
511   @param elem_size    Size (number of unknowns) per element
512   @param blk_size     Number of elements in a block
513   @param num_comp     Number of field components per interpolation node
514                         (1 for scalar fields)
515   @param comp_stride  Stride between components for the same L-vector "node".
516                         Data for node i, component j, element k can be found in
517                         the L-vector at index
518                         offsets[i + k*elem_size] + j*comp_stride.
519   @param l_size       The size of the L-vector. This vector may be larger than
520                         the elements and fields given by this restriction.
521   @param mem_type     Memory type of the @a offsets array, see CeedMemType
522   @param copy_mode    Copy mode for the @a offsets array, see CeedCopyMode
523   @param offsets      Array of shape [@a num_elem, @a elem_size]. Row i holds the
524                         ordered list of the offsets (into the input CeedVector)
525                         for the unknowns corresponding to element i, where
526                         0 <= i < @a num_elem. All offsets must be in the range
527                         [0, @a l_size - 1]. The backend will permute and pad this
528                         array to the desired ordering for the blocksize, which is
529                         typically given by the backend. The default reordering is
530                         to interlace elements.
531   @param rstr         Address of the variable where the newly created
532                         CeedElemRestriction will be stored
533 
534   @return An error code: 0 - success, otherwise - failure
535 
536   @ref Backend
537  **/
538 int CeedElemRestrictionCreateBlocked(Ceed ceed, CeedInt num_elem,
539                                      CeedInt elem_size,
540                                      CeedInt blk_size, CeedInt num_comp,
541                                      CeedInt comp_stride, CeedSize l_size,
542                                      CeedMemType mem_type, CeedCopyMode copy_mode,
543                                      const CeedInt *offsets,
544                                      CeedElemRestriction *rstr) {
545   int ierr;
546   CeedInt *blk_offsets;
547   CeedInt num_blk = (num_elem / blk_size) + !!(num_elem % blk_size);
548 
549   if (!ceed->ElemRestrictionCreateBlocked) {
550     Ceed delegate;
551     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
552     CeedChk(ierr);
553 
554     if (!delegate)
555       // LCOV_EXCL_START
556       return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support "
557                        "ElemRestrictionCreateBlocked");
558     // LCOV_EXCL_STOP
559 
560     ierr = CeedElemRestrictionCreateBlocked(delegate, num_elem, elem_size, blk_size,
561                                             num_comp, comp_stride, l_size, mem_type,
562                                             copy_mode, offsets, rstr);
563     CeedChk(ierr);
564     return CEED_ERROR_SUCCESS;
565   }
566 
567   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
568 
569   ierr = CeedCalloc(num_blk*blk_size*elem_size, &blk_offsets); CeedChk(ierr);
570   ierr = CeedPermutePadOffsets(offsets, blk_offsets, num_blk, num_elem, blk_size,
571                                elem_size); CeedChk(ierr);
572 
573   (*rstr)->ceed = ceed;
574   ierr = CeedReference(ceed); CeedChk(ierr);
575   (*rstr)->ref_count = 1;
576   (*rstr)->num_elem = num_elem;
577   (*rstr)->elem_size = elem_size;
578   (*rstr)->num_comp = num_comp;
579   (*rstr)->comp_stride = comp_stride;
580   (*rstr)->l_size = l_size;
581   (*rstr)->num_blk = num_blk;
582   (*rstr)->blk_size = blk_size;
583   (*rstr)->is_oriented = 0;
584   ierr = ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER,
585          (const CeedInt *) blk_offsets, *rstr); CeedChk(ierr);
586   if (copy_mode == CEED_OWN_POINTER) {
587     ierr = CeedFree(&offsets); CeedChk(ierr);
588   }
589   return CEED_ERROR_SUCCESS;
590 }
591 
592 /**
593   @brief Create a blocked strided CeedElemRestriction
594 
595   @param ceed       A Ceed object where the CeedElemRestriction will be created
596   @param num_elem   Number of elements described by the restriction
597   @param elem_size  Size (number of "nodes") per element
598   @param blk_size   Number of elements in a block
599   @param num_comp   Number of field components per interpolation node
600                       (1 for scalar fields)
601   @param l_size     The size of the L-vector. This vector may be larger than
602                       the elements and fields given by this restriction.
603   @param strides    Array for strides between [nodes, components, elements].
604                       Data for node i, component j, element k can be found in
605                       the L-vector at index
606                       i*strides[0] + j*strides[1] + k*strides[2].
607                       @a CEED_STRIDES_BACKEND may be used with vectors created
608                       by a Ceed backend.
609   @param rstr       Address of the variable where the newly created
610                       CeedElemRestriction will be stored
611 
612   @return An error code: 0 - success, otherwise - failure
613 
614   @ref User
615 **/
616 int CeedElemRestrictionCreateBlockedStrided(Ceed ceed, CeedInt num_elem,
617     CeedInt elem_size, CeedInt blk_size, CeedInt num_comp, CeedSize l_size,
618     const CeedInt strides[3], CeedElemRestriction *rstr) {
619   int ierr;
620   CeedInt num_blk = (num_elem / blk_size) + !!(num_elem % blk_size);
621 
622   if (!ceed->ElemRestrictionCreateBlocked) {
623     Ceed delegate;
624     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
625     CeedChk(ierr);
626 
627     if (!delegate)
628       // LCOV_EXCL_START
629       return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support "
630                        "ElemRestrictionCreateBlocked");
631     // LCOV_EXCL_STOP
632 
633     ierr = CeedElemRestrictionCreateBlockedStrided(delegate, num_elem, elem_size,
634            blk_size, num_comp, l_size, strides, rstr); CeedChk(ierr);
635     return CEED_ERROR_SUCCESS;
636   }
637 
638   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
639 
640   (*rstr)->ceed = ceed;
641   ierr = CeedReference(ceed); CeedChk(ierr);
642   (*rstr)->ref_count = 1;
643   (*rstr)->num_elem = num_elem;
644   (*rstr)->elem_size = elem_size;
645   (*rstr)->num_comp = num_comp;
646   (*rstr)->l_size = l_size;
647   (*rstr)->num_blk = num_blk;
648   (*rstr)->blk_size = blk_size;
649   (*rstr)->is_oriented = 0;
650   ierr = CeedMalloc(3, &(*rstr)->strides); CeedChk(ierr);
651   for (int i=0; i<3; i++)
652     (*rstr)->strides[i] = strides[i];
653   ierr = ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER,
654          NULL, *rstr); CeedChk(ierr);
655   return CEED_ERROR_SUCCESS;
656 }
657 
658 /**
659   @brief Copy the pointer to a CeedElemRestriction. Both pointers should
660            be destroyed with `CeedElemRestrictionDestroy()`;
661            Note: If `*rstr_copy` is non-NULL, then it is assumed that
662            `*rstr_copy` is a pointer to a CeedElemRestriction. This
663            CeedElemRestriction will be destroyed if `*rstr_copy` is the
664            only reference to this CeedElemRestriction.
665 
666   @param rstr            CeedElemRestriction to copy reference to
667   @param[out] rstr_copy  Variable to store copied reference
668 
669   @return An error code: 0 - success, otherwise - failure
670 
671   @ref User
672 **/
673 int CeedElemRestrictionReferenceCopy(CeedElemRestriction rstr,
674                                      CeedElemRestriction *rstr_copy) {
675   int ierr;
676 
677   ierr = CeedElemRestrictionReference(rstr); CeedChk(ierr);
678   ierr = CeedElemRestrictionDestroy(rstr_copy); CeedChk(ierr);
679   *rstr_copy = rstr;
680   return CEED_ERROR_SUCCESS;
681 }
682 
683 /**
684   @brief Create CeedVectors associated with a CeedElemRestriction
685 
686   @param rstr   CeedElemRestriction
687   @param l_vec  The address of the L-vector to be created, or NULL
688   @param e_vec  The address of the E-vector to be created, or NULL
689 
690   @return An error code: 0 - success, otherwise - failure
691 
692   @ref User
693 **/
694 int CeedElemRestrictionCreateVector(CeedElemRestriction rstr, CeedVector *l_vec,
695                                     CeedVector *e_vec) {
696   int ierr;
697   CeedSize e_size, l_size;
698   l_size = rstr->l_size;
699   e_size = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp;
700   if (l_vec) {
701     ierr = CeedVectorCreate(rstr->ceed, l_size, l_vec); CeedChk(ierr);
702   }
703   if (e_vec) {
704     ierr = CeedVectorCreate(rstr->ceed, e_size, e_vec); CeedChk(ierr);
705   }
706   return CEED_ERROR_SUCCESS;
707 }
708 
709 /**
710   @brief Restrict an L-vector to an E-vector or apply its transpose
711 
712   @param rstr    CeedElemRestriction
713   @param t_mode  Apply restriction or transpose
714   @param u       Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE)
715   @param ru      Output vector (of shape [@a num_elem * @a elem_size] when
716                    t_mode=@ref CEED_NOTRANSPOSE). Ordering of the e-vector is decided
717                    by the backend.
718   @param request Request or @ref CEED_REQUEST_IMMEDIATE
719 
720   @return An error code: 0 - success, otherwise - failure
721 
722   @ref User
723 **/
724 int CeedElemRestrictionApply(CeedElemRestriction rstr, CeedTransposeMode t_mode,
725                              CeedVector u, CeedVector ru,
726                              CeedRequest *request) {
727   CeedInt m, n;
728   int ierr;
729 
730   if (t_mode == CEED_NOTRANSPOSE) {
731     m = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp;
732     n = rstr->l_size;
733   } else {
734     m = rstr->l_size;
735     n = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp;
736   }
737   if (n != u->length)
738     // LCOV_EXCL_START
739     return CeedError(rstr->ceed, CEED_ERROR_DIMENSION,
740                      "Input vector size %d not compatible with "
741                      "element restriction (%d, %d)", u->length, m, n);
742   // LCOV_EXCL_STOP
743   if (m != ru->length)
744     // LCOV_EXCL_START
745     return CeedError(rstr->ceed, CEED_ERROR_DIMENSION,
746                      "Output vector size %d not compatible with "
747                      "element restriction (%d, %d)", ru->length, m, n);
748   // LCOV_EXCL_STOP
749   ierr = rstr->Apply(rstr, t_mode, u, ru, request); CeedChk(ierr);
750   return CEED_ERROR_SUCCESS;
751 }
752 
753 /**
754   @brief Restrict an L-vector to a block of an E-vector or apply its transpose
755 
756   @param rstr    CeedElemRestriction
757   @param block   Block number to restrict to/from, i.e. block=0 will handle
758                    elements [0 : blk_size] and block=3 will handle elements
759                    [3*blk_size : 4*blk_size]
760   @param t_mode  Apply restriction or transpose
761   @param u       Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE)
762   @param ru      Output vector (of shape [@a blk_size * @a elem_size] when
763                    t_mode=@ref CEED_NOTRANSPOSE). Ordering of the e-vector is decided
764                    by the backend.
765   @param request Request or @ref CEED_REQUEST_IMMEDIATE
766 
767   @return An error code: 0 - success, otherwise - failure
768 
769   @ref Backend
770 **/
771 int CeedElemRestrictionApplyBlock(CeedElemRestriction rstr, CeedInt block,
772                                   CeedTransposeMode t_mode, CeedVector u,
773                                   CeedVector ru, CeedRequest *request) {
774   CeedInt m, n;
775   int ierr;
776 
777   if (t_mode == CEED_NOTRANSPOSE) {
778     m = rstr->blk_size * rstr->elem_size * rstr->num_comp;
779     n = rstr->l_size;
780   } else {
781     m = rstr->l_size;
782     n = rstr->blk_size * rstr->elem_size * rstr->num_comp;
783   }
784   if (n != u->length)
785     // LCOV_EXCL_START
786     return CeedError(rstr->ceed, CEED_ERROR_DIMENSION,
787                      "Input vector size %d not compatible with "
788                      "element restriction (%d, %d)", u->length, m, n);
789   // LCOV_EXCL_STOP
790   if (m != ru->length)
791     // LCOV_EXCL_START
792     return CeedError(rstr->ceed, CEED_ERROR_DIMENSION,
793                      "Output vector size %d not compatible with "
794                      "element restriction (%d, %d)", ru->length, m, n);
795   // LCOV_EXCL_STOP
796   if (rstr->blk_size*block > rstr->num_elem)
797     // LCOV_EXCL_START
798     return CeedError(rstr->ceed, CEED_ERROR_DIMENSION,
799                      "Cannot retrieve block %d, element %d > "
800                      "total elements %d", block, rstr->blk_size*block,
801                      rstr->num_elem);
802   // LCOV_EXCL_STOP
803   ierr = rstr->ApplyBlock(rstr, block, t_mode, u, ru, request);
804   CeedChk(ierr);
805   return CEED_ERROR_SUCCESS;
806 }
807 
808 /**
809   @brief Get the Ceed associated with a CeedElemRestriction
810 
811   @param rstr       CeedElemRestriction
812   @param[out] ceed  Variable to store Ceed
813 
814   @return An error code: 0 - success, otherwise - failure
815 
816   @ref Advanced
817 **/
818 int CeedElemRestrictionGetCeed(CeedElemRestriction rstr, Ceed *ceed) {
819   *ceed = rstr->ceed;
820   return CEED_ERROR_SUCCESS;
821 }
822 
823 /**
824   @brief Get the L-vector component stride
825 
826   @param rstr              CeedElemRestriction
827   @param[out] comp_stride  Variable to store component stride
828 
829   @return An error code: 0 - success, otherwise - failure
830 
831   @ref Advanced
832 **/
833 int CeedElemRestrictionGetCompStride(CeedElemRestriction rstr,
834                                      CeedInt *comp_stride) {
835   *comp_stride = rstr->comp_stride;
836   return CEED_ERROR_SUCCESS;
837 }
838 
839 /**
840   @brief Get the total number of elements in the range of a CeedElemRestriction
841 
842   @param rstr           CeedElemRestriction
843   @param[out] num_elem  Variable to store number of elements
844 
845   @return An error code: 0 - success, otherwise - failure
846 
847   @ref Advanced
848 **/
849 int CeedElemRestrictionGetNumElements(CeedElemRestriction rstr,
850                                       CeedInt *num_elem) {
851   *num_elem = rstr->num_elem;
852   return CEED_ERROR_SUCCESS;
853 }
854 
855 /**
856   @brief Get the size of elements in the CeedElemRestriction
857 
858   @param rstr            CeedElemRestriction
859   @param[out] elem_size  Variable to store size of elements
860 
861   @return An error code: 0 - success, otherwise - failure
862 
863   @ref Advanced
864 **/
865 int CeedElemRestrictionGetElementSize(CeedElemRestriction rstr,
866                                       CeedInt *elem_size) {
867   *elem_size = rstr->elem_size;
868   return CEED_ERROR_SUCCESS;
869 }
870 
871 /**
872   @brief Get the size of the l-vector for a CeedElemRestriction
873 
874   @param rstr         CeedElemRestriction
875   @param[out] l_size  Variable to store number of nodes
876 
877   @return An error code: 0 - success, otherwise - failure
878 
879   @ref Advanced
880 **/
881 int CeedElemRestrictionGetLVectorSize(CeedElemRestriction rstr,
882                                       CeedSize *l_size) {
883   *l_size = rstr->l_size;
884   return CEED_ERROR_SUCCESS;
885 }
886 
887 /**
888   @brief Get the number of components in the elements of a
889          CeedElemRestriction
890 
891   @param rstr           CeedElemRestriction
892   @param[out] num_comp  Variable to store number of components
893 
894   @return An error code: 0 - success, otherwise - failure
895 
896   @ref Advanced
897 **/
898 int CeedElemRestrictionGetNumComponents(CeedElemRestriction rstr,
899                                         CeedInt *num_comp) {
900   *num_comp = rstr->num_comp;
901   return CEED_ERROR_SUCCESS;
902 }
903 
904 /**
905   @brief Get the number of blocks in a CeedElemRestriction
906 
907   @param rstr            CeedElemRestriction
908   @param[out] num_block  Variable to store number of blocks
909 
910   @return An error code: 0 - success, otherwise - failure
911 
912   @ref Advanced
913 **/
914 int CeedElemRestrictionGetNumBlocks(CeedElemRestriction rstr,
915                                     CeedInt *num_block) {
916   *num_block = rstr->num_blk;
917   return CEED_ERROR_SUCCESS;
918 }
919 
920 /**
921   @brief Get the size of blocks in the CeedElemRestriction
922 
923   @param rstr           CeedElemRestriction
924   @param[out] blk_size  Variable to store size of blocks
925 
926   @return An error code: 0 - success, otherwise - failure
927 
928   @ref Advanced
929 **/
930 int CeedElemRestrictionGetBlockSize(CeedElemRestriction rstr,
931                                     CeedInt *blk_size) {
932   *blk_size = rstr->blk_size;
933   return CEED_ERROR_SUCCESS;
934 }
935 
936 /**
937   @brief Get the multiplicity of nodes in a CeedElemRestriction
938 
939   @param rstr       CeedElemRestriction
940   @param[out] mult  Vector to store multiplicity (of size l_size)
941 
942   @return An error code: 0 - success, otherwise - failure
943 
944   @ref User
945 **/
946 int CeedElemRestrictionGetMultiplicity(CeedElemRestriction rstr,
947                                        CeedVector mult) {
948   int ierr;
949   CeedVector e_vec;
950 
951   // Create e_vec to hold intermediate computation in E^T (E 1)
952   ierr = CeedElemRestrictionCreateVector(rstr, NULL, &e_vec); CeedChk(ierr);
953 
954   // Compute e_vec = E * 1
955   ierr = CeedVectorSetValue(mult, 1.0); CeedChk(ierr);
956   ierr = CeedElemRestrictionApply(rstr, CEED_NOTRANSPOSE, mult, e_vec,
957                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
958   // Compute multiplicity, mult = E^T * e_vec = E^T (E 1)
959   ierr = CeedVectorSetValue(mult, 0.0); CeedChk(ierr);
960   ierr = CeedElemRestrictionApply(rstr, CEED_TRANSPOSE, e_vec, mult,
961                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
962   // Cleanup
963   ierr = CeedVectorDestroy(&e_vec); CeedChk(ierr);
964   return CEED_ERROR_SUCCESS;
965 }
966 
967 /**
968   @brief View a CeedElemRestriction
969 
970   @param[in] rstr    CeedElemRestriction to view
971   @param[in] stream  Stream to write; typically stdout/stderr or a file
972 
973   @return Error code: 0 - success, otherwise - failure
974 
975   @ref User
976 **/
977 int CeedElemRestrictionView(CeedElemRestriction rstr, FILE *stream) {
978   char stridesstr[500];
979   if (rstr->strides)
980     sprintf(stridesstr, "[%d, %d, %d]", rstr->strides[0], rstr->strides[1],
981             rstr->strides[2]);
982   else
983     sprintf(stridesstr, "%d", rstr->comp_stride);
984 
985   fprintf(stream, "%sCeedElemRestriction from (%td, %d) to %d elements with %d "
986           "nodes each and %s %s\n", rstr->blk_size > 1 ? "Blocked " : "",
987           rstr->l_size, rstr->num_comp, rstr->num_elem, rstr->elem_size,
988           rstr->strides ? "strides" : "component stride", stridesstr);
989   return CEED_ERROR_SUCCESS;
990 }
991 
992 /**
993   @brief Destroy a CeedElemRestriction
994 
995   @param rstr  CeedElemRestriction to destroy
996 
997   @return An error code: 0 - success, otherwise - failure
998 
999   @ref User
1000 **/
1001 int CeedElemRestrictionDestroy(CeedElemRestriction *rstr) {
1002   int ierr;
1003 
1004   if (!*rstr || --(*rstr)->ref_count > 0) return CEED_ERROR_SUCCESS;
1005   if ((*rstr)->num_readers)
1006     // LCOV_EXCL_START
1007     return CeedError((*rstr)->ceed, CEED_ERROR_ACCESS,
1008                      "Cannot destroy CeedElemRestriction, "
1009                      "a process has read access to the offset data");
1010   // LCOV_EXCL_STOP
1011   if ((*rstr)->Destroy) {
1012     ierr = (*rstr)->Destroy(*rstr); CeedChk(ierr);
1013   }
1014   ierr = CeedFree(&(*rstr)->strides); CeedChk(ierr);
1015   ierr = CeedDestroy(&(*rstr)->ceed); CeedChk(ierr);
1016   ierr = CeedFree(rstr); CeedChk(ierr);
1017   return CEED_ERROR_SUCCESS;
1018 }
1019 
1020 /// @}
1021