xref: /libCEED/interface/ceed-elemrestriction.c (revision 9a00868b5066558afb121f7066045d7511a0e1e3)
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 
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 imode      Ordering of the ncomp components, i.e. it specifies
182                       the ordering of the components of the L-vector used
183                       by this CeedElemRestriction. CEED_NONINTERLACED indicates
184                       the component is the outermost index and CEED_INTERLACED
185                       indicates the component is the innermost index in
186                       ordering of the L-vector.
187   @param nelem      Number of elements described in the @a indices array
188   @param elemsize   Size (number of "nodes") per element
189   @param nnodes     The number of nodes in the L-vector. The input CeedVector
190                       to which the restriction will be applied is of size
191                       @a nnodes * @a ncomp. This size may include data
192                       used by other CeedElemRestriction objects describing
193                       different types of elements.
194   @param ncomp      Number of field components per interpolation node
195                       (1 for scalar fields)
196   @param mtype      Memory type of the @a indices array, see CeedMemType
197   @param cmode      Copy mode for the @a indices array, see CeedCopyMode
198   @param indices    Array of shape [@a nelem, @a elemsize]. Row i holds the
199                       ordered list of the indices (into the input CeedVector)
200                       for the unknowns corresponding to element i, where
201                       0 <= i < @a nelem. All indices must be in the range
202                       [0, @a nnodes - 1].
203   @param[out] rstr  Address of the variable where the newly created
204                       CeedElemRestriction will be stored
205 
206   @return An error code: 0 - success, otherwise - failure
207 
208   @ref User
209 **/
210 int CeedElemRestrictionCreate(Ceed ceed, CeedInterlaceMode imode,
211                               CeedInt nelem, CeedInt elemsize, CeedInt nnodes,
212                               CeedInt ncomp, CeedMemType mtype,
213                               CeedCopyMode cmode, const CeedInt *indices,
214                               CeedElemRestriction *rstr) {
215   int ierr;
216 
217   if (!ceed->ElemRestrictionCreate) {
218     Ceed delegate;
219     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
220     CeedChk(ierr);
221 
222     if (!delegate)
223       // LCOV_EXCL_START
224       return CeedError(ceed, 1, "Backend does not support ElemRestrictionCreate");
225     // LCOV_EXCL_STOP
226 
227     ierr = CeedElemRestrictionCreate(delegate, imode, nelem, elemsize,
228                                      nnodes, ncomp, mtype, cmode,
229                                      indices, rstr); CeedChk(ierr);
230     return 0;
231   }
232 
233   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
234   (*rstr)->ceed = ceed;
235   ceed->refcount++;
236   (*rstr)->refcount = 1;
237   (*rstr)->imode = imode;
238   (*rstr)->nelem = nelem;
239   (*rstr)->elemsize = elemsize;
240   (*rstr)->nnodes = nnodes;
241   (*rstr)->ncomp = ncomp;
242   (*rstr)->nblk = nelem;
243   (*rstr)->blksize = 1;
244   ierr = ceed->ElemRestrictionCreate(mtype, cmode, indices, *rstr); CeedChk(ierr);
245   return 0;
246 }
247 
248 /**
249   @brief Create a strided CeedElemRestriction
250 
251   @param ceed       A Ceed object where the CeedElemRestriction will be created
252   @param nelem      Number of elements described by the restriction
253   @param elemsize   Size (number of "nodes") per element
254   @param nnodes     The number of nodes in the L-vector. The input CeedVector
255                       to which the restriction will be applied is of size
256                       @a nnodes * @a ncomp. This size may include data
257                       used by other CeedElemRestriction objects describing
258                       different types of elements.
259   @param ncomp      Number of field components per interpolation node
260                       (1 for scalar fields)
261   @param strides    Array for strides between [nodes, components, elements].
262                       The data for node i, component j, element k in the
263                       L-vector is given by
264                         i*strides[0] + j*strides[1] + k*strides[2]
265   @param rstr       Address of the variable where the newly created
266                       CeedElemRestriction will be stored
267 
268   @return An error code: 0 - success, otherwise - failure
269 
270   @ref User
271 **/
272 int CeedElemRestrictionCreateStrided(Ceed ceed, CeedInt nelem, CeedInt elemsize,
273                                      CeedInt nnodes, CeedInt ncomp,
274                                      const CeedInt strides[3],
275                                      CeedElemRestriction *rstr) {
276   int ierr;
277 
278   if (!ceed->ElemRestrictionCreate) {
279     Ceed delegate;
280     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
281     CeedChk(ierr);
282 
283     if (!delegate)
284       // LCOV_EXCL_START
285       return CeedError(ceed, 1, "Backend does not support ElemRestrictionCreate");
286     // LCOV_EXCL_STOP
287 
288     ierr = CeedElemRestrictionCreateStrided(delegate, nelem, elemsize, nnodes,
289                                             ncomp, strides, rstr); CeedChk(ierr);
290     return 0;
291   }
292 
293   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
294   (*rstr)->ceed = ceed;
295   ceed->refcount++;
296   (*rstr)->refcount = 1;
297   (*rstr)->nelem = nelem;
298   (*rstr)->elemsize = elemsize;
299   (*rstr)->nnodes = nnodes;
300   (*rstr)->ncomp = ncomp;
301   (*rstr)->nblk = nelem;
302   (*rstr)->blksize = 1;
303   ierr = CeedMalloc(3, &(*rstr)->strides); CeedChk(ierr);
304   for (int i = 0; i<3; i++)
305     (*rstr)->strides[i] = strides[i];
306   ierr = ceed->ElemRestrictionCreate(CEED_MEM_HOST, CEED_OWN_POINTER, NULL,
307                                      *rstr);
308   CeedChk(ierr);
309   return 0;
310 }
311 
312 /**
313   @brief Create a blocked CeedElemRestriction, typically only called by backends
314 
315   @param ceed       A Ceed object where the CeedElemRestriction will be created.
316   @param imode      Ordering of the ncomp components, i.e. it specifies
317                       the ordering of the components of the L-vector used
318                       by this CeedElemRestriction. CEED_NONINTERLACED indicates
319                       the component is the outermost index and CEED_INTERLACED
320                       indicates the component is the innermost index in
321                       ordering of the L-vector.
322   @param nelem      Number of elements described in the @a indices array.
323   @param elemsize   Size (number of unknowns) per element
324   @param blksize    Number of elements in a block
325   @param nnodes     The number of nodes in the L-vector. The input CeedVector
326                       to which the restriction will be applied is of size
327                       @a nnodes * @a ncomp. This size may include data
328                       used by other CeedElemRestriction objects describing
329                       different types of elements.
330   @param ncomp      Number of field components per interpolation node
331                       (1 for scalar fields)
332   @param mtype      Memory type of the @a indices array, see CeedMemType
333   @param cmode      Copy mode for the @a indices array, see CeedCopyMode
334   @param indices    Array of shape [@a nelem, @a elemsize]. Row i holds the
335                       ordered list of the indices (into the input CeedVector)
336                       for the unknowns corresponding to element i, where
337                       0 <= i < @a nelem. All indices must be in the range
338                       [0, @a nnodes). The backend will permute and pad this
339                       array to the desired ordering for the blocksize, which is
340                       typically given by the backend. The default reordering is
341                       to interlace elements.
342   @param rstr       Address of the variable where the newly created
343                       CeedElemRestriction will be stored
344 
345   @return An error code: 0 - success, otherwise - failure
346 
347   @ref Backend
348  **/
349 int CeedElemRestrictionCreateBlocked(Ceed ceed,  CeedInterlaceMode imode,
350                                      CeedInt nelem, CeedInt elemsize,
351                                      CeedInt blksize, CeedInt nnodes,
352                                      CeedInt ncomp, CeedMemType mtype,
353                                      CeedCopyMode cmode, const CeedInt *indices,
354                                      CeedElemRestriction *rstr) {
355   int ierr;
356   CeedInt *blkindices;
357   CeedInt nblk = (nelem / blksize) + !!(nelem % blksize);
358 
359   if (!ceed->ElemRestrictionCreateBlocked) {
360     Ceed delegate;
361     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
362     CeedChk(ierr);
363 
364     if (!delegate)
365       // LCOV_EXCL_START
366       return CeedError(ceed, 1, "Backend does not support "
367                        "ElemRestrictionCreateBlocked");
368     // LCOV_EXCL_STOP
369 
370     ierr = CeedElemRestrictionCreateBlocked(delegate, imode, nelem, elemsize,
371                                             blksize, nnodes, ncomp, mtype, cmode,
372                                             indices, rstr); CeedChk(ierr);
373     return 0;
374   }
375 
376   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
377 
378   ierr = CeedCalloc(nblk*blksize*elemsize, &blkindices); CeedChk(ierr);
379   ierr = CeedPermutePadIndices(indices, blkindices, nblk, nelem, blksize,
380                                elemsize);
381   CeedChk(ierr);
382 
383   (*rstr)->ceed = ceed;
384   ceed->refcount++;
385   (*rstr)->refcount = 1;
386   (*rstr)->imode = imode;
387   (*rstr)->nelem = nelem;
388   (*rstr)->elemsize = elemsize;
389   (*rstr)->nnodes = nnodes;
390   (*rstr)->ncomp = ncomp;
391   (*rstr)->nblk = nblk;
392   (*rstr)->blksize = blksize;
393   ierr = ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER,
394          (const CeedInt *) blkindices, *rstr); CeedChk(ierr);
395 
396   if (cmode == CEED_OWN_POINTER) {
397     ierr = CeedFree(&indices); CeedChk(ierr);
398   }
399 
400   return 0;
401 }
402 
403 /**
404   @brief Create a blocked strided CeedElemRestriction
405 
406   @param ceed       A Ceed object where the CeedElemRestriction will be created
407   @param nelem      Number of elements described by the restriction
408   @param elemsize   Size (number of "nodes") per element
409   @param blksize    Number of elements in a block
410   @param nnodes     The number of nodes in the L-vector. The input CeedVector
411                       to which the restriction will be applied is of size
412                       @a nnodes * @a ncomp. This size may include data
413                       used by other CeedElemRestriction objects describing
414                       different types of elements.
415   @param ncomp      Number of field components per interpolation node
416                       (1 for scalar fields)
417   @param strides    Array for strides between [nodes, components, elements].
418                       The data for node i, component j, element k in the
419                       L-vector is given by
420                         i*strides[0] + j*strides[1] + k*strides[2]
421   @param rstr       Address of the variable where the newly created
422                       CeedElemRestriction will be stored
423 
424   @return An error code: 0 - success, otherwise - failure
425 
426   @ref User
427 **/
428 int CeedElemRestrictionCreateBlockedStrided(Ceed ceed, CeedInt nelem,
429     CeedInt elemsize, CeedInt blksize, CeedInt nnodes, CeedInt ncomp,
430     const CeedInt strides[3], CeedElemRestriction *rstr) {
431   int ierr;
432   CeedInt nblk = (nelem / blksize) + !!(nelem % blksize);
433 
434   if (!ceed->ElemRestrictionCreateBlocked) {
435     Ceed delegate;
436     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
437     CeedChk(ierr);
438 
439     if (!delegate)
440       // LCOV_EXCL_START
441       return CeedError(ceed, 1, "Backend does not support "
442                        "ElemRestrictionCreateBlocked");
443     // LCOV_EXCL_STOP
444 
445     ierr = CeedElemRestrictionCreateBlockedStrided(delegate, nelem, elemsize,
446            blksize, nnodes, ncomp, strides, rstr);
447     CeedChk(ierr);
448     return 0;
449   }
450 
451   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
452 
453   (*rstr)->ceed = ceed;
454   ceed->refcount++;
455   (*rstr)->refcount = 1;
456   (*rstr)->nelem = nelem;
457   (*rstr)->elemsize = elemsize;
458   (*rstr)->nnodes = nnodes;
459   (*rstr)->ncomp = ncomp;
460   (*rstr)->nblk = nblk;
461   (*rstr)->blksize = blksize;
462   ierr = CeedMalloc(3, &(*rstr)->strides); CeedChk(ierr);
463   for (int i = 0; i<3; i++)
464     (*rstr)->strides[i] = strides[i];
465   ierr = ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER,
466          NULL, *rstr); CeedChk(ierr);
467 
468   return 0;
469 }
470 
471 /**
472   @brief Create CeedVectors associated with a CeedElemRestriction
473 
474   @param rstr  CeedElemRestriction
475   @param lvec  The address of the L-vector to be created, or NULL
476   @param evec  The address of the E-vector to be created, or NULL
477 
478   @return An error code: 0 - success, otherwise - failure
479 
480   @ref User
481 **/
482 int CeedElemRestrictionCreateVector(CeedElemRestriction rstr, CeedVector *lvec,
483                                     CeedVector *evec) {
484   int ierr;
485   CeedInt n, m;
486   m = rstr->nnodes * rstr->ncomp;
487   n = rstr->nblk * rstr->blksize * rstr->elemsize * rstr->ncomp;
488   if (lvec) {
489     ierr = CeedVectorCreate(rstr->ceed, m, lvec); CeedChk(ierr);
490   }
491   if (evec) {
492     ierr = CeedVectorCreate(rstr->ceed, n, evec); CeedChk(ierr);
493   }
494   return 0;
495 }
496 
497 /**
498   @brief Restrict an L-vector to an E-vector or apply its transpose
499 
500   @param rstr    CeedElemRestriction
501   @param tmode   Apply restriction or transpose
502   @param u       Input vector (of shape [@a nnodes, @a ncomp] when
503                    tmode=CEED_NOTRANSPOSE, imode=CEED_INTERLACED)
504   @param ru      Output vector (of shape [@a nelem * @a elemsize] when
505                    tmode=CEED_NOTRANSPOSE). Ordering of the e-vector is decided
506                    by the backend.
507   @param request Request or CEED_REQUEST_IMMEDIATE
508 
509   @return An error code: 0 - success, otherwise - failure
510 
511   @ref User
512 **/
513 int CeedElemRestrictionApply(CeedElemRestriction rstr, CeedTransposeMode tmode,
514                              CeedVector u, CeedVector ru,
515                              CeedRequest *request) {
516   CeedInt m,n;
517   int ierr;
518 
519   if (tmode == CEED_NOTRANSPOSE) {
520     m = rstr->nblk * rstr->blksize * rstr->elemsize * rstr->ncomp;
521     n = rstr->nnodes * rstr->ncomp;
522   } else {
523     m = rstr->nnodes * rstr->ncomp;
524     n = rstr->nblk * rstr->blksize * rstr->elemsize * rstr->ncomp;
525   }
526   if (n != u->length)
527     // LCOV_EXCL_START
528     return CeedError(rstr->ceed, 2, "Input vector size %d not compatible with "
529                      "element restriction (%d, %d)", u->length, m, n);
530   // LCOV_EXCL_STOP
531   if (m != ru->length)
532     // LCOV_EXCL_START
533     return CeedError(rstr->ceed, 2, "Output vector size %d not compatible with "
534                      "element restriction (%d, %d)", ru->length, m, n);
535   // LCOV_EXCL_STOP
536   ierr = rstr->Apply(rstr, tmode, u, ru, request); CeedChk(ierr);
537 
538   return 0;
539 }
540 
541 /**
542   @brief Restrict an L-vector to a block of an E-vector or apply its transpose
543 
544   @param rstr    CeedElemRestriction
545   @param block   Block number to restrict to/from, i.e. block=0 will handle
546                    elements [0 : blksize] and block=3 will handle elements
547                    [3*blksize : 4*blksize]
548   @param tmode   Apply restriction or transpose
549   @param u       Input vector (of shape [@a nnodes, @a ncomp] when
550                    tmode=CEED_NOTRANSPOSE, imode=CEED_INTERLACED)
551   @param ru      Output vector (of shape [@a blksize * @a elemsize] when
552                    tmode=CEED_NOTRANSPOSE). Ordering of the e-vector is decided
553                    by the backend.
554   @param request Request or CEED_REQUEST_IMMEDIATE
555 
556   @return An error code: 0 - success, otherwise - failure
557 
558   @ref Backend
559 **/
560 int CeedElemRestrictionApplyBlock(CeedElemRestriction rstr, CeedInt block,
561                                   CeedTransposeMode tmode, CeedVector u,
562                                   CeedVector ru, CeedRequest *request) {
563   CeedInt m,n;
564   int ierr;
565 
566   if (tmode == CEED_NOTRANSPOSE) {
567     m = rstr->blksize * rstr->elemsize * rstr->ncomp;
568     n = rstr->nnodes * rstr->ncomp;
569   } else {
570     m = rstr->nnodes * rstr->ncomp;
571     n = rstr->blksize * rstr->elemsize * rstr->ncomp;
572   }
573   if (n != u->length)
574     // LCOV_EXCL_START
575     return CeedError(rstr->ceed, 2, "Input vector size %d not compatible with "
576                      "element restriction (%d, %d)", u->length, m, n);
577   // LCOV_EXCL_STOP
578   if (m != ru->length)
579     // LCOV_EXCL_START
580     return CeedError(rstr->ceed, 2, "Output vector size %d not compatible with "
581                      "element restriction (%d, %d)", ru->length, m, n);
582   // LCOV_EXCL_STOP
583   if (rstr->blksize*block > rstr->nelem)
584     // LCOV_EXCL_START
585     return CeedError(rstr->ceed, 2, "Cannot retrieve block %d, element %d > "
586                      "total elements %d", block, rstr->blksize*block,
587                      rstr->nelem);
588   // LCOV_EXCL_STOP
589   ierr = rstr->ApplyBlock(rstr, block, tmode, u, ru, request);
590   CeedChk(ierr);
591 
592   return 0;
593 }
594 
595 /**
596   @brief Get the L-vector interlaced mode of a CeedElemRestriction
597 
598   @param rstr             CeedElemRestriction
599   @param[out] imode       Variable to store imode
600 
601   @return An error code: 0 - success, otherwise - failure
602 
603   @ref Backend
604 **/
605 int CeedElemRestrictionGetIMode(CeedElemRestriction rstr,
606                                 CeedInterlaceMode *imode) {
607   *imode = rstr->imode;
608   return 0;
609 }
610 
611 /**
612   @brief Get the total number of elements in the range of a CeedElemRestriction
613 
614   @param rstr             CeedElemRestriction
615   @param[out] numelem     Variable to store number of elements
616 
617   @return An error code: 0 - success, otherwise - failure
618 
619   @ref Backend
620 **/
621 int CeedElemRestrictionGetNumElements(CeedElemRestriction rstr,
622                                       CeedInt *numelem) {
623   *numelem = rstr->nelem;
624   return 0;
625 }
626 
627 /**
628   @brief Get the size of elements in the CeedElemRestriction
629 
630   @param rstr             CeedElemRestriction
631   @param[out] elemsize    Variable to store size of elements
632 
633   @return An error code: 0 - success, otherwise - failure
634 
635   @ref Backend
636 **/
637 int CeedElemRestrictionGetElementSize(CeedElemRestriction rstr,
638                                       CeedInt *elemsize) {
639   *elemsize = rstr->elemsize;
640   return 0;
641 }
642 
643 /**
644   @brief Get the number of degrees of freedom in the range of a
645          CeedElemRestriction
646 
647   @param rstr             CeedElemRestriction
648   @param[out] numnodes    Variable to store number of nodes
649 
650   @return An error code: 0 - success, otherwise - failure
651 
652   @ref Backend
653 **/
654 int CeedElemRestrictionGetNumNodes(CeedElemRestriction rstr,
655                                    CeedInt *numnodes) {
656   *numnodes = rstr->nnodes;
657   return 0;
658 }
659 
660 /**
661   @brief Get the number of components in the elements of a
662          CeedElemRestriction
663 
664   @param rstr             CeedElemRestriction
665   @param[out] numcomp     Variable to store number of components
666 
667   @return An error code: 0 - success, otherwise - failure
668 
669   @ref Backend
670 **/
671 int CeedElemRestrictionGetNumComponents(CeedElemRestriction rstr,
672                                         CeedInt *numcomp) {
673   *numcomp = rstr->ncomp;
674   return 0;
675 }
676 
677 /**
678   @brief Get the number of blocks in a CeedElemRestriction
679 
680   @param rstr             CeedElemRestriction
681   @param[out] numblock    Variable to store number of blocks
682 
683   @return An error code: 0 - success, otherwise - failure
684 
685   @ref Backend
686 **/
687 int CeedElemRestrictionGetNumBlocks(CeedElemRestriction rstr,
688                                     CeedInt *numblock) {
689   *numblock = rstr->nblk;
690   return 0;
691 }
692 
693 /**
694   @brief Get the size of blocks in the CeedElemRestriction
695 
696   @param rstr             CeedElemRestriction
697   @param[out] blksize     Variable to store size of blocks
698 
699   @return An error code: 0 - success, otherwise - failure
700 
701   @ref Backend
702 **/
703 int CeedElemRestrictionGetBlockSize(CeedElemRestriction rstr,
704                                     CeedInt *blksize) {
705   *blksize = rstr->blksize;
706   return 0;
707 }
708 
709 /**
710   @brief Get the multiplicity of nodes in a CeedElemRestriction
711 
712   @param rstr             CeedElemRestriction
713   @param[out] mult        Vector to store multiplicity (of size nnodes*ncomp)
714 
715   @return An error code: 0 - success, otherwise - failure
716 
717   @ref User
718 **/
719 int CeedElemRestrictionGetMultiplicity(CeedElemRestriction rstr,
720                                        CeedVector mult) {
721   int ierr;
722   CeedVector evec;
723 
724   // Create and set evec
725   ierr = CeedElemRestrictionCreateVector(rstr, NULL, &evec); CeedChk(ierr);
726   ierr = CeedVectorSetValue(evec, 1.0); CeedChk(ierr);
727   ierr = CeedVectorSetValue(mult, 0.0); CeedChk(ierr);
728 
729   // Apply to get multiplicity
730   ierr = CeedElemRestrictionApply(rstr, CEED_TRANSPOSE, evec, mult,
731                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
732 
733   // Cleanup
734   ierr = CeedVectorDestroy(&evec); CeedChk(ierr);
735 
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