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