xref: /libCEED/interface/ceed-elemrestriction.c (revision 7ed52d01ec037ec8310375bd921b20a1514ec747)
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-impl.h>
18 #include <ceed-backend.h>
19 
20 /// @file
21 /// Implementation of public CeedElemRestriction interfaces
22 ///
23 /// @addtogroup CeedElemRestriction
24 /// @{
25 
26 /**
27   @brief Create a CeedElemRestriction
28 
29   @param ceed       A Ceed object where the CeedElemRestriction will be created
30   @param imode      Ordering of the ncomp components, i.e. it specifies
31                       the ordering of the components of the L-vector used
32                       by this CeedElemRestriction. CEED_NONINTERLACED indicates
33                       the component is the outermost index and CEED_INTERLACED
34                       indicates the component is the innermost index in
35                       ordering of the L-vector.
36   @param nelem      Number of elements described in the @a indices array
37   @param elemsize   Size (number of "nodes") per element
38   @param nnodes     The number of nodes in the L-vector. The input CeedVector
39                       to which the restriction will be applied is of size
40                       @a nnodes * @a ncomp. This size may include data
41                       used by other CeedElemRestriction objects describing
42                       different types of elements.
43   @param ncomp      Number of field components per interpolation node
44                       (1 for scalar fields)
45   @param mtype      Memory type of the @a indices array, see CeedMemType
46   @param cmode      Copy mode for the @a indices array, see CeedCopyMode
47   @param indices    Array of shape [@a nelem, @a elemsize]. Row i holds the
48                       ordered list of the indices (into the input CeedVector)
49                       for the unknowns corresponding to element i, where
50                       0 <= i < @a nelem. All indices must be in the range
51                       [0, @a nnodes - 1].
52   @param[out] rstr  Address of the variable where the newly created
53                       CeedElemRestriction will be stored
54 
55   @return An error code: 0 - success, otherwise - failure
56 
57   @ref Basic
58 **/
59 int CeedElemRestrictionCreate(Ceed ceed, CeedInterlaceMode imode,
60                               CeedInt nelem, CeedInt elemsize, CeedInt nnodes,
61                               CeedInt ncomp, CeedMemType mtype,
62                               CeedCopyMode cmode, const CeedInt *indices,
63                               CeedElemRestriction *rstr) {
64   int ierr;
65 
66   if (!ceed->ElemRestrictionCreate) {
67     Ceed delegate;
68     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
69     CeedChk(ierr);
70 
71     if (!delegate)
72       // LCOV_EXCL_START
73       return CeedError(ceed, 1, "Backend does not support ElemRestrictionCreate");
74     // LCOV_EXCL_STOP
75 
76     ierr = CeedElemRestrictionCreate(delegate, imode, nelem, elemsize,
77                                      nnodes, ncomp, mtype, cmode,
78                                      indices, rstr); CeedChk(ierr);
79     return 0;
80   }
81 
82   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
83   (*rstr)->ceed = ceed;
84   ceed->refcount++;
85   (*rstr)->refcount = 1;
86   (*rstr)->imode = imode;
87   (*rstr)->nelem = nelem;
88   (*rstr)->elemsize = elemsize;
89   (*rstr)->nnodes = nnodes;
90   (*rstr)->ncomp = ncomp;
91   (*rstr)->nblk = nelem;
92   (*rstr)->blksize = 1;
93   ierr = ceed->ElemRestrictionCreate(mtype, cmode, indices, *rstr); CeedChk(ierr);
94   return 0;
95 }
96 
97 /**
98   @brief Create a strided CeedElemRestriction
99 
100   @param ceed       A Ceed object where the CeedElemRestriction will be created
101   @param nelem      Number of elements described by the restriction
102   @param elemsize   Size (number of "nodes") per element
103   @param nnodes     The number of nodes in the L-vector. The input CeedVector
104                       to which the restriction will be applied is of size
105                       @a nnodes * @a ncomp. This size may include data
106                       used by other CeedElemRestriction objects describing
107                       different types of elements.
108   @param ncomp      Number of field components per interpolation node
109                       (1 for scalar fields)
110   @param strides    Array for strides between [nodes, components, elements].
111                       The data for node i, component j, element k in the
112                       L-vector is given by
113                         i*strides[0] + j*strides[1] + k*strides[2]
114   @param rstr       Address of the variable where the newly created
115                       CeedElemRestriction will be stored
116 
117   @return An error code: 0 - success, otherwise - failure
118 
119   @ref Basic
120 **/
121 int CeedElemRestrictionCreateStrided(Ceed ceed, CeedInt nelem, CeedInt elemsize,
122                                      CeedInt nnodes, CeedInt ncomp,
123                                      CeedInt strides[3],
124                                      CeedElemRestriction *rstr) {
125   int ierr;
126 
127   if (!ceed->ElemRestrictionCreate) {
128     Ceed delegate;
129     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
130     CeedChk(ierr);
131 
132     if (!delegate)
133       // LCOV_EXCL_START
134       return CeedError(ceed, 1, "Backend does not support ElemRestrictionCreate");
135     // LCOV_EXCL_STOP
136 
137     ierr = CeedElemRestrictionCreateStrided(delegate, nelem, elemsize, nnodes,
138                                             ncomp, strides, rstr); CeedChk(ierr);
139     return 0;
140   }
141 
142   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
143   (*rstr)->ceed = ceed;
144   ceed->refcount++;
145   (*rstr)->refcount = 1;
146   (*rstr)->nelem = nelem;
147   (*rstr)->elemsize = elemsize;
148   (*rstr)->nnodes = nnodes;
149   (*rstr)->ncomp = ncomp;
150   (*rstr)->nblk = nelem;
151   (*rstr)->blksize = 1;
152   ierr = CeedMalloc(3, &(*rstr)->strides); CeedChk(ierr);
153   for (int i = 0; i<3; i++)
154     (*rstr)->strides[i] = strides[i];
155   ierr = ceed->ElemRestrictionCreate(CEED_MEM_HOST, CEED_OWN_POINTER, NULL,
156                                      *rstr);
157   CeedChk(ierr);
158   return 0;
159 }
160 
161 /**
162   @brief Permute and pad indices for a blocked restriction
163 
164   @param indices    Array of shape [@a nelem, @a elemsize]. Row i holds the
165                       ordered list of the indices (into the input CeedVector)
166                       for the unknowns corresponding to element i, where
167                       0 <= i < @a nelem. All indices must be in the range
168                       [0, @a nnodes).
169   @param blkindices Array of permuted and padded indices of
170                       shape [@a nblk, @a elemsize, @a blksize].
171   @param nblk       Number of blocks
172   @param nelem      Number of elements
173   @param blksize    Number of elements in a block
174   @param elemsize   Size of each element
175 
176   @return An error code: 0 - success, otherwise - failure
177 
178   @ref Utility
179 **/
180 int CeedPermutePadIndices(const CeedInt *indices, CeedInt *blkindices,
181                           CeedInt nblk, CeedInt nelem, CeedInt blksize,
182                           CeedInt elemsize) {
183   for (CeedInt e = 0; e < nblk*blksize; e+=blksize)
184     for (int j = 0; j < blksize; j++)
185       for (int k = 0; k < elemsize; k++)
186         blkindices[e*elemsize + k*blksize + j]
187           = indices[CeedIntMin(e+j,nelem-1)*elemsize + k];
188   return 0;
189 }
190 
191 /**
192   @brief Create a blocked CeedElemRestriction, typically only called by backends
193 
194   @param ceed       A Ceed object where the CeedElemRestriction will be created.
195   @param imode      Ordering of the ncomp components, i.e. it specifies
196                       the ordering of the components of the L-vector used
197                       by this CeedElemRestriction. CEED_NONINTERLACED indicates
198                       the component is the outermost index and CEED_INTERLACED
199                       indicates the component is the innermost index in
200                       ordering of the L-vector.
201   @param nelem      Number of elements described in the @a indices array.
202   @param elemsize   Size (number of unknowns) per element
203   @param blksize    Number of elements in a block
204   @param nnodes     The number of nodes in the L-vector. The input CeedVector
205                       to which the restriction will be applied is of size
206                       @a nnodes * @a ncomp. This size may include data
207                       used by other CeedElemRestriction objects describing
208                       different types of elements.
209   @param ncomp      Number of field components per interpolation node
210                       (1 for scalar fields)
211   @param mtype      Memory type of the @a indices array, see CeedMemType
212   @param cmode      Copy mode for the @a indices array, see CeedCopyMode
213   @param indices    Array of shape [@a nelem, @a elemsize]. Row i holds the
214                       ordered list of the indices (into the input CeedVector)
215                       for the unknowns corresponding to element i, where
216                       0 <= i < @a nelem. All indices must be in the range
217                       [0, @a nnodes). The backend will permute and pad this
218                       array to the desired ordering for the blocksize, which is
219                       typically given by the backend. The default reordering is
220                       to interlace elements.
221   @param rstr       Address of the variable where the newly created
222                       CeedElemRestriction will be stored
223 
224   @return An error code: 0 - success, otherwise - failure
225 
226   @ref Advanced
227  **/
228 int CeedElemRestrictionCreateBlocked(Ceed ceed,  CeedInterlaceMode imode,
229                                      CeedInt nelem, CeedInt elemsize,
230                                      CeedInt blksize, CeedInt nnodes,
231                                      CeedInt ncomp, CeedMemType mtype,
232                                      CeedCopyMode cmode, const CeedInt *indices,
233                                      CeedElemRestriction *rstr) {
234   int ierr;
235   CeedInt *blkindices;
236   CeedInt nblk = (nelem / blksize) + !!(nelem % blksize);
237 
238   if (!ceed->ElemRestrictionCreateBlocked) {
239     Ceed delegate;
240     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
241     CeedChk(ierr);
242 
243     if (!delegate)
244       // LCOV_EXCL_START
245       return CeedError(ceed, 1, "Backend does not support "
246                        "ElemRestrictionCreateBlocked");
247     // LCOV_EXCL_STOP
248 
249     ierr = CeedElemRestrictionCreateBlocked(delegate, imode, nelem, elemsize,
250                                             blksize, nnodes, ncomp, mtype, cmode,
251                                             indices, rstr); CeedChk(ierr);
252     return 0;
253   }
254 
255   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
256 
257   ierr = CeedCalloc(nblk*blksize*elemsize, &blkindices); CeedChk(ierr);
258   ierr = CeedPermutePadIndices(indices, blkindices, nblk, nelem, blksize,
259                                elemsize);
260   CeedChk(ierr);
261 
262   (*rstr)->ceed = ceed;
263   ceed->refcount++;
264   (*rstr)->refcount = 1;
265   (*rstr)->imode = imode;
266   (*rstr)->nelem = nelem;
267   (*rstr)->elemsize = elemsize;
268   (*rstr)->nnodes = nnodes;
269   (*rstr)->ncomp = ncomp;
270   (*rstr)->nblk = nblk;
271   (*rstr)->blksize = blksize;
272   ierr = ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER,
273          (const CeedInt *) blkindices, *rstr); CeedChk(ierr);
274 
275   if (cmode == CEED_OWN_POINTER) {
276     ierr = CeedFree(&indices); CeedChk(ierr);
277   }
278 
279   return 0;
280 }
281 
282 /**
283   @brief Create a blocked strided CeedElemRestriction
284 
285   @param ceed       A Ceed object where the CeedElemRestriction will be created
286   @param nelem      Number of elements described by the restriction
287   @param elemsize   Size (number of "nodes") per element
288   @param blksize    Number of elements in a block
289   @param nnodes     The number of nodes in the L-vector. The input CeedVector
290                       to which the restriction will be applied is of size
291                       @a nnodes * @a ncomp. This size may include data
292                       used by other CeedElemRestriction objects describing
293                       different types of elements.
294   @param ncomp      Number of field components per interpolation node
295                       (1 for scalar fields)
296   @param strides    Array for strides between [nodes, components, elements].
297                       The data for node i, component j, element k in the
298                       L-vector is given by
299                         i*strides[0] + j*strides[1] + k*strides[2]
300   @param rstr       Address of the variable where the newly created
301                       CeedElemRestriction will be stored
302 
303   @return An error code: 0 - success, otherwise - failure
304 
305   @ref Basic
306 **/
307 int CeedElemRestrictionCreateBlockedStrided(Ceed ceed, CeedInt nelem,
308     CeedInt elemsize, CeedInt blksize,
309     CeedInt nnodes, CeedInt ncomp,
310     CeedInt strides[3],
311     CeedElemRestriction *rstr) {
312   int ierr;
313   CeedInt nblk = (nelem / blksize) + !!(nelem % blksize);
314 
315   if (!ceed->ElemRestrictionCreateBlocked) {
316     Ceed delegate;
317     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
318     CeedChk(ierr);
319 
320     if (!delegate)
321       // LCOV_EXCL_START
322       return CeedError(ceed, 1, "Backend does not support "
323                        "ElemRestrictionCreateBlocked");
324     // LCOV_EXCL_STOP
325 
326     ierr = CeedElemRestrictionCreateBlockedStrided(delegate, nelem, elemsize,
327            blksize, nnodes, ncomp,
328            strides, rstr);
329     CeedChk(ierr);
330     return 0;
331   }
332 
333   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
334 
335   (*rstr)->ceed = ceed;
336   ceed->refcount++;
337   (*rstr)->refcount = 1;
338   (*rstr)->nelem = nelem;
339   (*rstr)->elemsize = elemsize;
340   (*rstr)->nnodes = nnodes;
341   (*rstr)->ncomp = ncomp;
342   (*rstr)->nblk = nblk;
343   (*rstr)->blksize = blksize;
344   ierr = CeedMalloc(3, &(*rstr)->strides); CeedChk(ierr);
345   for (int i = 0; i<3; i++)
346     (*rstr)->strides[i] = strides[i];
347   ierr = ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER,
348          NULL, *rstr); CeedChk(ierr);
349 
350   return 0;
351 }
352 
353 /**
354   @brief Create CeedVectors associated with a CeedElemRestriction
355 
356   @param rstr  CeedElemRestriction
357   @param lvec  The address of the L-vector to be created, or NULL
358   @param evec  The address of the E-vector to be created, or NULL
359 
360   @return An error code: 0 - success, otherwise - failure
361 
362   @ref Advanced
363 **/
364 int CeedElemRestrictionCreateVector(CeedElemRestriction rstr, CeedVector *lvec,
365                                     CeedVector *evec) {
366   int ierr;
367   CeedInt n, m;
368   m = rstr->nnodes * rstr->ncomp;
369   n = rstr->nblk * rstr->blksize * rstr->elemsize * rstr->ncomp;
370   if (lvec) {
371     ierr = CeedVectorCreate(rstr->ceed, m, lvec); CeedChk(ierr);
372   }
373   if (evec) {
374     ierr = CeedVectorCreate(rstr->ceed, n, evec); CeedChk(ierr);
375   }
376   return 0;
377 }
378 
379 /**
380   @brief Restrict an L-vector to an E-vector or apply its transpose
381 
382   @param rstr    CeedElemRestriction
383   @param tmode   Apply restriction or transpose
384   @param u       Input vector (of shape [@a nnodes, @a ncomp] when
385                    tmode=CEED_NOTRANSPOSE, imode=CEED_INTERLACED)
386   @param ru      Output vector (of shape [@a nelem * @a elemsize] when
387                    tmode=CEED_NOTRANSPOSE). Ordering of the e-vector is decided
388                    by the backend.
389   @param request Request or CEED_REQUEST_IMMEDIATE
390 
391   @return An error code: 0 - success, otherwise - failure
392 
393   @ref Advanced
394 **/
395 int CeedElemRestrictionApply(CeedElemRestriction rstr, CeedTransposeMode tmode,
396                              CeedVector u, CeedVector ru,
397                              CeedRequest *request) {
398   CeedInt m,n;
399   int ierr;
400 
401   if (tmode == CEED_NOTRANSPOSE) {
402     m = rstr->nblk * rstr->blksize * rstr->elemsize * rstr->ncomp;
403     n = rstr->nnodes * rstr->ncomp;
404   } else {
405     m = rstr->nnodes * rstr->ncomp;
406     n = rstr->nblk * rstr->blksize * rstr->elemsize * rstr->ncomp;
407   }
408   if (n != u->length)
409     // LCOV_EXCL_START
410     return CeedError(rstr->ceed, 2, "Input vector size %d not compatible with "
411                      "element restriction (%d, %d)", u->length, m, n);
412   // LCOV_EXCL_STOP
413   if (m != ru->length)
414     // LCOV_EXCL_START
415     return CeedError(rstr->ceed, 2, "Output vector size %d not compatible with "
416                      "element restriction (%d, %d)", ru->length, m, n);
417   // LCOV_EXCL_STOP
418   ierr = rstr->Apply(rstr, tmode, u, ru, request); CeedChk(ierr);
419 
420   return 0;
421 }
422 
423 /**
424   @brief Restrict an L-vector to a block of an E-vector or apply its transpose
425 
426   @param rstr    CeedElemRestriction
427   @param block   Block number to restrict to/from, i.e. block=0 will handle
428                    elements [0 : blksize] and block=3 will handle elements
429                    [3*blksize : 4*blksize]
430   @param tmode   Apply restriction or transpose
431   @param u       Input vector (of shape [@a nnodes, @a ncomp] when
432                    tmode=CEED_NOTRANSPOSE, imode=CEED_INTERLACED)
433   @param ru      Output vector (of shape [@a blksize * @a elemsize] when
434                    tmode=CEED_NOTRANSPOSE). Ordering of the e-vector is decided
435                    by the backend.
436   @param request Request or CEED_REQUEST_IMMEDIATE
437 
438   @return An error code: 0 - success, otherwise - failure
439 
440   @ref Advanced
441 **/
442 int CeedElemRestrictionApplyBlock(CeedElemRestriction rstr, CeedInt block,
443                                   CeedTransposeMode tmode, CeedVector u,
444                                   CeedVector ru, CeedRequest *request) {
445   CeedInt m,n;
446   int ierr;
447 
448   if (tmode == CEED_NOTRANSPOSE) {
449     m = rstr->blksize * rstr->elemsize * rstr->ncomp;
450     n = rstr->nnodes * rstr->ncomp;
451   } else {
452     m = rstr->nnodes * rstr->ncomp;
453     n = rstr->blksize * rstr->elemsize * rstr->ncomp;
454   }
455   if (n != u->length)
456     // LCOV_EXCL_START
457     return CeedError(rstr->ceed, 2, "Input vector size %d not compatible with "
458                      "element restriction (%d, %d)", u->length, m, n);
459   // LCOV_EXCL_STOP
460   if (m != ru->length)
461     // LCOV_EXCL_START
462     return CeedError(rstr->ceed, 2, "Output vector size %d not compatible with "
463                      "element restriction (%d, %d)", ru->length, m, n);
464   // LCOV_EXCL_STOP
465   if (rstr->blksize*block > rstr->nelem)
466     // LCOV_EXCL_START
467     return CeedError(rstr->ceed, 2, "Cannot retrieve block %d, element %d > "
468                      "total elements %d", block, rstr->blksize*block,
469                      rstr->nelem);
470   // LCOV_EXCL_STOP
471   ierr = rstr->ApplyBlock(rstr, block, tmode, u, ru, request);
472   CeedChk(ierr);
473 
474   return 0;
475 }
476 
477 /**
478   @brief Get the multiplicity of nodes in a CeedElemRestriction
479 
480   @param rstr             CeedElemRestriction
481   @param[out] mult        Vector to store multiplicity (of size nnodes*ncomp)
482 
483   @return An error code: 0 - success, otherwise - failure
484 
485   @ref Advanced
486 **/
487 int CeedElemRestrictionGetMultiplicity(CeedElemRestriction rstr,
488                                        CeedVector mult) {
489   int ierr;
490   CeedVector evec;
491 
492   // Create and set evec
493   ierr = CeedElemRestrictionCreateVector(rstr, NULL, &evec); CeedChk(ierr);
494   ierr = CeedVectorSetValue(evec, 1.0); CeedChk(ierr);
495   ierr = CeedVectorSetValue(mult, 0.0); CeedChk(ierr);
496 
497   // Apply to get multiplicity
498   ierr = CeedElemRestrictionApply(rstr, CEED_TRANSPOSE, evec, mult,
499                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
500 
501   // Cleanup
502   ierr = CeedVectorDestroy(&evec); CeedChk(ierr);
503 
504   return 0;
505 }
506 
507 /**
508   @brief Get the Ceed associated with a CeedElemRestriction
509 
510   @param rstr             CeedElemRestriction
511   @param[out] ceed        Variable to store Ceed
512 
513   @return An error code: 0 - success, otherwise - failure
514 
515   @ref Advanced
516 **/
517 int CeedElemRestrictionGetCeed(CeedElemRestriction rstr, Ceed *ceed) {
518   *ceed = rstr->ceed;
519   return 0;
520 }
521 
522 /**
523   @brief Get the L-vector interlaced mode of a CeedElemRestriction
524 
525   @param rstr             CeedElemRestriction
526   @param[out] imode       Variable to store imode
527 
528   @return An error code: 0 - success, otherwise - failure
529 
530   @ref Advanced
531 **/
532 int CeedElemRestrictionGetIMode(CeedElemRestriction rstr,
533                                 CeedInterlaceMode *imode) {
534   if (rstr->strides)
535     // LCOV_EXCL_START
536     return CeedError(rstr->ceed, 1, "Strided ElemRestriction has no interlace "
537                      "mode");
538   // LCOV_EXCL_STOP
539 
540   *imode = rstr->imode;
541   return 0;
542 }
543 
544 /**
545   @brief Get the total number of elements in the range of a CeedElemRestriction
546 
547   @param rstr             CeedElemRestriction
548   @param[out] numelem     Variable to store number of elements
549 
550   @return An error code: 0 - success, otherwise - failure
551 
552   @ref Advanced
553 **/
554 int CeedElemRestrictionGetNumElements(CeedElemRestriction rstr,
555                                       CeedInt *numelem) {
556   *numelem = rstr->nelem;
557   return 0;
558 }
559 
560 /**
561   @brief Get the size of elements in the CeedElemRestriction
562 
563   @param rstr             CeedElemRestriction
564   @param[out] elemsize    Variable to store size of elements
565 
566   @return An error code: 0 - success, otherwise - failure
567 
568   @ref Advanced
569 **/
570 int CeedElemRestrictionGetElementSize(CeedElemRestriction rstr,
571                                       CeedInt *elemsize) {
572   *elemsize = rstr->elemsize;
573   return 0;
574 }
575 
576 /**
577   @brief Get the number of degrees of freedom in the range of a
578          CeedElemRestriction
579 
580   @param rstr             CeedElemRestriction
581   @param[out] numnodes    Variable to store number of nodes
582 
583   @return An error code: 0 - success, otherwise - failure
584 
585   @ref Advanced
586 **/
587 int CeedElemRestrictionGetNumNodes(CeedElemRestriction rstr,
588                                    CeedInt *numnodes) {
589   *numnodes = rstr->nnodes;
590   return 0;
591 }
592 
593 /**
594   @brief Get the number of components in the elements of a
595          CeedElemRestriction
596 
597   @param rstr             CeedElemRestriction
598   @param[out] numcomp     Variable to store number of components
599 
600   @return An error code: 0 - success, otherwise - failure
601 
602   @ref Advanced
603 **/
604 int CeedElemRestrictionGetNumComponents(CeedElemRestriction rstr,
605                                         CeedInt *numcomp) {
606   *numcomp = rstr->ncomp;
607   return 0;
608 }
609 
610 /**
611   @brief Get the number of blocks in a CeedElemRestriction
612 
613   @param rstr             CeedElemRestriction
614   @param[out] numblock    Variable to store number of blocks
615 
616   @return An error code: 0 - success, otherwise - failure
617 
618   @ref Advanced
619 **/
620 int CeedElemRestrictionGetNumBlocks(CeedElemRestriction rstr,
621                                     CeedInt *numblock) {
622   *numblock = rstr->nblk;
623   return 0;
624 }
625 
626 /**
627   @brief Get the size of blocks in the CeedElemRestriction
628 
629   @param rstr             CeedElemRestriction
630   @param[out] blksize     Variable to store size of blocks
631 
632   @return An error code: 0 - success, otherwise - failure
633 
634   @ref Advanced
635 **/
636 int CeedElemRestrictionGetBlockSize(CeedElemRestriction rstr,
637                                     CeedInt *blksize) {
638   *blksize = rstr->blksize;
639   return 0;
640 }
641 
642 /**
643   @brief Get the strides of a strided CeedElemRestriction
644 
645   @param rstr             CeedElemRestriction
646   @param[out] strides     Variable to store strides array
647 
648   @return An error code: 0 - success, otherwise - failure
649 
650   @ref Advanced
651 **/
652 int CeedElemRestrictionGetStrides(CeedElemRestriction rstr,
653                                   CeedInt (*strides)[3]) {
654   if (!rstr->strides)
655     // LCOV_EXCL_START
656     return CeedError(rstr->ceed, 1, "ElemRestriction has no stride data");
657   // LCOV_EXCL_STOP
658 
659   for (int i = 0; i<3; i++)
660     (*strides)[i] = rstr->strides[i];
661   return 0;
662 }
663 
664 /**
665   @brief Get the backend stride status of a CeedElemRestriction
666 
667   @param rstr             CeedElemRestriction
668   @param[out] bool        Variable to store stride status
669 
670   @return An error code: 0 - success, otherwise - failure
671 
672   @ref Advanced
673 **/
674 int CeedElemRestrictionGetBackendStridesStatus(CeedElemRestriction rstr,
675     bool *status) {
676   if (!rstr->strides)
677     // LCOV_EXCL_START
678     return CeedError(rstr->ceed, 1, "ElemRestriction has no stride data");
679   // LCOV_EXCL_STOP
680 
681   *status = ((rstr->strides[0] == CEED_STRIDES_BACKEND[0]) &&
682              (rstr->strides[1] == CEED_STRIDES_BACKEND[1]) &&
683              (rstr->strides[2] == CEED_STRIDES_BACKEND[2]));
684   return 0;
685 }
686 
687 /**
688   @brief Get the backend data of a CeedElemRestriction
689 
690   @param rstr             CeedElemRestriction
691   @param[out] data        Variable to store data
692 
693   @return An error code: 0 - success, otherwise - failure
694 
695   @ref Advanced
696 **/
697 int CeedElemRestrictionGetData(CeedElemRestriction rstr, void **data) {
698   *data = rstr->data;
699   return 0;
700 }
701 
702 /**
703   @brief Set the backend data of a CeedElemRestriction
704 
705   @param[out] rstr        CeedElemRestriction
706   @param data             Data to set
707 
708   @return An error code: 0 - success, otherwise - failure
709 
710   @ref Advanced
711 **/
712 int CeedElemRestrictionSetData(CeedElemRestriction rstr, void **data) {
713   rstr->data = *data;
714   return 0;
715 }
716 
717 /**
718   @brief View a CeedElemRestriction
719 
720   @param[in] rstr    CeedElemRestriction to view
721   @param[in] stream  Stream to write; typically stdout/stderr or a file
722 
723   @return Error code: 0 - success, otherwise - failure
724 
725   @ref Utility
726 **/
727 int CeedElemRestrictionView(CeedElemRestriction rstr, FILE *stream) {
728   char stridesstr[500];
729   if (rstr->strides)
730     sprintf(stridesstr, "[%d, %d, %d]", rstr->strides[0], rstr->strides[1],
731             rstr->strides[2]);
732 
733   fprintf(stream, "%sCeedElemRestriction from (%d, %d) to %d elements with %d "
734           "nodes each and %s %s\n", rstr->blksize > 1 ? "Blocked " : "",
735           rstr->nnodes, rstr->ncomp, rstr->nelem, rstr->elemsize,
736           rstr->strides ? "strides" : "L-vector components",
737           rstr->strides ? stridesstr : CeedInterlaceModes[rstr->imode]);
738   return 0;
739 }
740 
741 /**
742   @brief Destroy a CeedElemRestriction
743 
744   @param rstr  CeedElemRestriction to destroy
745 
746   @return An error code: 0 - success, otherwise - failure
747 
748   @ref Basic
749 **/
750 int CeedElemRestrictionDestroy(CeedElemRestriction *rstr) {
751   int ierr;
752 
753   if (!*rstr || --(*rstr)->refcount > 0)
754     return 0;
755   if ((*rstr)->Destroy) {
756     ierr = (*rstr)->Destroy(*rstr); CeedChk(ierr);
757   }
758   ierr = CeedFree(&(*rstr)->strides); CeedChk(ierr);
759   ierr = CeedDestroy(&(*rstr)->ceed); CeedChk(ierr);
760   ierr = CeedFree(rstr); CeedChk(ierr);
761   return 0;
762 }
763 
764 /// @cond DOXYGEN_SKIP
765 // Indicate that the stride is determined by the backend
766 CeedInt CEED_STRIDES_BACKEND[3] = {};
767 /// @endcond
768 
769 /// @}
770