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