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