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