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