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