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