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