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