xref: /libCEED/interface/ceed-elemrestriction.c (revision cdf95791513f7c35170bef3ba2e19f272fe04533)
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/ceed.h>
18 #include <ceed/backend.h>
19 #include <ceed-impl.h>
20 #include <stdbool.h>
21 #include <stdio.h>
22 
23 /// @file
24 /// Implementation of CeedElemRestriction interfaces
25 
26 /// ----------------------------------------------------------------------------
27 /// CeedElemRestriction Library Internal Functions
28 /// ----------------------------------------------------------------------------
29 /// @addtogroup CeedElemRestrictionDeveloper
30 /// @{
31 
32 /**
33   @brief Permute and pad offsets for a blocked restriction
34 
35   @param offsets     Array of shape [@a num_elem, @a elem_size]. Row i holds the
36                        ordered list of the offsets (into the input CeedVector)
37                        for the unknowns corresponding to element i, where
38                        0 <= i < @a num_elem. All offsets must be in the range
39                        [0, @a l_size - 1].
40   @param blk_offsets Array of permuted and padded offsets of
41                        shape [@a num_blk, @a elem_size, @a blk_size].
42   @param num_blk     Number of blocks
43   @param num_elem    Number of elements
44   @param blk_size    Number of elements in a block
45   @param elem_size   Size of each element
46 
47   @return An error code: 0 - success, otherwise - failure
48 
49   @ref Utility
50 **/
51 int CeedPermutePadOffsets(const CeedInt *offsets, CeedInt *blk_offsets,
52                           CeedInt num_blk, CeedInt num_elem, CeedInt blk_size,
53                           CeedInt elem_size) {
54   for (CeedInt e=0; e<num_blk*blk_size; e+=blk_size)
55     for (int j=0; j<blk_size; j++)
56       for (int k=0; k<elem_size; k++)
57         blk_offsets[e*elem_size + k*blk_size + j]
58           = offsets[CeedIntMin(e+j,num_elem-1)*elem_size + k];
59   return CEED_ERROR_SUCCESS;
60 }
61 
62 /// @}
63 
64 /// ----------------------------------------------------------------------------
65 /// CeedElemRestriction Backend API
66 /// ----------------------------------------------------------------------------
67 /// @addtogroup CeedElemRestrictionBackend
68 /// @{
69 
70 /**
71 
72   @brief Get the strides of a strided CeedElemRestriction
73 
74   @param rstr          CeedElemRestriction
75   @param[out] strides  Variable to store strides array
76 
77   @return An error code: 0 - success, otherwise - failure
78 
79   @ref Backend
80 **/
81 int CeedElemRestrictionGetStrides(CeedElemRestriction rstr,
82                                   CeedInt (*strides)[3]) {
83   if (!rstr->strides)
84     // LCOV_EXCL_START
85     return CeedError(rstr->ceed, CEED_ERROR_MINOR,
86                      "ElemRestriction has no stride data");
87   // LCOV_EXCL_STOP
88 
89   for (int i=0; i<3; i++)
90     (*strides)[i] = rstr->strides[i];
91   return CEED_ERROR_SUCCESS;
92 }
93 
94 /**
95   @brief Get read-only access to a CeedElemRestriction offsets array by memtype
96 
97   @param rstr          CeedElemRestriction to retrieve offsets
98   @param mem_type      Memory type on which to access the array.  If the backend
99                          uses a different memory type, this will perform a copy
100                          (possibly cached).
101   @param[out] offsets  Array on memory type mem_type
102 
103   @return An error code: 0 - success, otherwise - failure
104 
105   @ref User
106 **/
107 int CeedElemRestrictionGetOffsets(CeedElemRestriction rstr,
108                                   CeedMemType mem_type,
109                                   const CeedInt **offsets) {
110   int ierr;
111 
112   if (!rstr->GetOffsets)
113     // LCOV_EXCL_START
114     return CeedError(rstr->ceed, CEED_ERROR_UNSUPPORTED,
115                      "Backend does not support GetOffsets");
116   // LCOV_EXCL_STOP
117 
118   ierr = rstr->GetOffsets(rstr, mem_type, offsets); CeedChk(ierr);
119   rstr->num_readers++;
120   return CEED_ERROR_SUCCESS;
121 }
122 
123 /**
124   @brief Restore an offsets array obtained using CeedElemRestrictionGetOffsets()
125 
126   @param rstr     CeedElemRestriction to restore
127   @param offsets  Array of offset data
128 
129   @return An error code: 0 - success, otherwise - failure
130 
131   @ref User
132 **/
133 int CeedElemRestrictionRestoreOffsets(CeedElemRestriction rstr,
134                                       const CeedInt **offsets) {
135   *offsets = NULL;
136   rstr->num_readers--;
137   return CEED_ERROR_SUCCESS;
138 }
139 
140 /**
141   @brief Get the strided status of a CeedElemRestriction
142 
143   @param rstr             CeedElemRestriction
144   @param[out] is_strided  Variable to store strided status, 1 if strided else 0
145 
146   @return An error code: 0 - success, otherwise - failure
147 
148   @ref Backend
149 **/
150 int CeedElemRestrictionIsStrided(CeedElemRestriction rstr, bool *is_strided) {
151   *is_strided = rstr->strides ? true : false;
152   return CEED_ERROR_SUCCESS;
153 }
154 
155 /**
156   @brief Get oriented status of a CeedElemRestriction
157 
158   @param rstr             CeedElemRestriction
159   @param[out] is_oriented  Variable to store oriented status, 1 if oriented else 0
160 
161   @return An error code: 0 - success, otherwise - failure
162 
163   @ref Backend
164 **/
165 int CeedElemRestrictionIsOriented(CeedElemRestriction rstr, bool *is_oriented) {
166   *is_oriented = rstr->is_oriented;
167   return CEED_ERROR_SUCCESS;
168 }
169 
170 /**
171   @brief Get the backend stride status of a CeedElemRestriction
172 
173   @param rstr                      CeedElemRestriction
174   @param[out] has_backend_strides  Variable to store stride status
175 
176   @return An error code: 0 - success, otherwise - failure
177 
178   @ref Backend
179 **/
180 int CeedElemRestrictionHasBackendStrides(CeedElemRestriction rstr,
181     bool *has_backend_strides) {
182   if (!rstr->strides)
183     // LCOV_EXCL_START
184     return CeedError(rstr->ceed, CEED_ERROR_MINOR,
185                      "ElemRestriction has no stride data");
186   // LCOV_EXCL_STOP
187 
188   *has_backend_strides = ((rstr->strides[0] == CEED_STRIDES_BACKEND[0]) &&
189                           (rstr->strides[1] == CEED_STRIDES_BACKEND[1]) &&
190                           (rstr->strides[2] == CEED_STRIDES_BACKEND[2]));
191   return CEED_ERROR_SUCCESS;
192 }
193 
194 /**
195 
196   @brief Get the E-vector layout of a CeedElemRestriction
197 
198   @param rstr         CeedElemRestriction
199   @param[out] layout  Variable to store layout array,
200                         stored as [nodes, components, elements].
201                         The data for node i, component j, element k in the
202                         E-vector is given by
203                         i*layout[0] + j*layout[1] + k*layout[2]
204 
205   @return An error code: 0 - success, otherwise - failure
206 
207   @ref Backend
208 **/
209 int CeedElemRestrictionGetELayout(CeedElemRestriction rstr,
210                                   CeedInt (*layout)[3]) {
211   if (!rstr->layout[0])
212     // LCOV_EXCL_START
213     return CeedError(rstr->ceed, CEED_ERROR_MINOR,
214                      "ElemRestriction has no layout data");
215   // LCOV_EXCL_STOP
216 
217   for (int i=0; i<3; i++)
218     (*layout)[i] = rstr->layout[i];
219   return CEED_ERROR_SUCCESS;
220 }
221 
222 /**
223 
224   @brief Set the E-vector layout of a CeedElemRestriction
225 
226   @param rstr    CeedElemRestriction
227   @param layout  Variable to containing layout array,
228                    stored as [nodes, components, elements].
229                    The data for node i, component j, element k in the
230                    E-vector is given by
231                    i*layout[0] + j*layout[1] + k*layout[2]
232 
233   @return An error code: 0 - success, otherwise - failure
234 
235   @ref Backend
236 **/
237 int CeedElemRestrictionSetELayout(CeedElemRestriction rstr,
238                                   CeedInt layout[3]) {
239   for (int i = 0; i<3; i++)
240     rstr->layout[i] = layout[i];
241   return CEED_ERROR_SUCCESS;
242 }
243 
244 /**
245   @brief Get the backend data of a CeedElemRestriction
246 
247   @param rstr       CeedElemRestriction
248   @param[out] data  Variable to store data
249 
250   @return An error code: 0 - success, otherwise - failure
251 
252   @ref Backend
253 **/
254 int CeedElemRestrictionGetData(CeedElemRestriction rstr, void *data) {
255   *(void **)data = rstr->data;
256   return CEED_ERROR_SUCCESS;
257 }
258 
259 /**
260   @brief Set the backend data of a CeedElemRestriction
261 
262   @param[out] rstr  CeedElemRestriction
263   @param data       Data to set
264 
265   @return An error code: 0 - success, otherwise - failure
266 
267   @ref Backend
268 **/
269 int CeedElemRestrictionSetData(CeedElemRestriction rstr, void *data) {
270   rstr->data = data;
271   return CEED_ERROR_SUCCESS;
272 }
273 
274 /**
275   @brief Increment the reference counter for a CeedElemRestriction
276 
277   @param rstr  ElemRestriction to increment the reference counter
278 
279   @return An error code: 0 - success, otherwise - failure
280 
281   @ref Backend
282 **/
283 int CeedElemRestrictionReference(CeedElemRestriction rstr) {
284   rstr->ref_count++;
285   return CEED_ERROR_SUCCESS;
286 }
287 
288 /// @}
289 
290 /// @cond DOXYGEN_SKIP
291 static struct CeedElemRestriction_private ceed_elemrestriction_none;
292 /// @endcond
293 
294 /// ----------------------------------------------------------------------------
295 /// CeedElemRestriction Public API
296 /// ----------------------------------------------------------------------------
297 /// @addtogroup CeedElemRestrictionUser
298 /// @{
299 
300 /// Indicate that the stride is determined by the backend
301 const CeedInt CEED_STRIDES_BACKEND[3] = {0};
302 
303 /// Indicate that no CeedElemRestriction is provided by the user
304 const CeedElemRestriction CEED_ELEMRESTRICTION_NONE =
305   &ceed_elemrestriction_none;
306 
307 /**
308   @brief Create a CeedElemRestriction
309 
310   @param ceed         A Ceed object where the CeedElemRestriction will be created
311   @param num_elem     Number of elements described in the @a offsets array
312   @param elem_size    Size (number of "nodes") per element
313   @param num_comp     Number of field components per interpolation node
314                         (1 for scalar fields)
315   @param comp_stride  Stride between components for the same L-vector "node".
316                         Data for node i, component j, element k can be found in
317                         the L-vector at index
318                         offsets[i + k*elem_size] + j*comp_stride.
319   @param l_size       The size of the L-vector. This vector may be larger than
320                         the elements and fields given by this restriction.
321   @param mem_type     Memory type of the @a offsets array, see CeedMemType
322   @param copy_mode    Copy mode for the @a offsets array, see CeedCopyMode
323   @param offsets      Array of shape [@a num_elem, @a elem_size]. Row i holds the
324                         ordered list of the offsets (into the input CeedVector)
325                         for the unknowns corresponding to element i, where
326                         0 <= i < @a num_elem. All offsets must be in the range
327                         [0, @a l_size - 1].
328   @param[out] rstr    Address of the variable where the newly created
329                         CeedElemRestriction will be stored
330 
331   @return An error code: 0 - success, otherwise - failure
332 
333   @ref User
334 **/
335 int CeedElemRestrictionCreate(Ceed ceed, CeedInt num_elem, CeedInt elem_size,
336                               CeedInt num_comp, CeedInt comp_stride,
337                               CeedInt l_size, CeedMemType mem_type,
338                               CeedCopyMode copy_mode, const CeedInt *offsets,
339                               CeedElemRestriction *rstr) {
340   int ierr;
341 
342   if (!ceed->ElemRestrictionCreate) {
343     Ceed delegate;
344     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
345     CeedChk(ierr);
346 
347     if (!delegate)
348       // LCOV_EXCL_START
349       return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
350                        "Backend does not support ElemRestrictionCreate");
351     // LCOV_EXCL_STOP
352 
353     ierr = CeedElemRestrictionCreate(delegate, num_elem, elem_size, num_comp,
354                                      comp_stride, l_size, mem_type, copy_mode,
355                                      offsets, rstr); CeedChk(ierr);
356     return CEED_ERROR_SUCCESS;
357   }
358 
359   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
360   (*rstr)->ceed = ceed;
361   ierr = CeedReference(ceed); CeedChk(ierr);
362   (*rstr)->ref_count = 1;
363   (*rstr)->num_elem = num_elem;
364   (*rstr)->elem_size = elem_size;
365   (*rstr)->num_comp = num_comp;
366   (*rstr)->comp_stride = comp_stride;
367   (*rstr)->l_size = l_size;
368   (*rstr)->num_blk = num_elem;
369   (*rstr)->blk_size = 1;
370   (*rstr)->is_oriented = 0;
371   ierr = ceed->ElemRestrictionCreate(mem_type, copy_mode, offsets, *rstr);
372   CeedChk(ierr);
373   return CEED_ERROR_SUCCESS;
374 }
375 
376 /**
377   @brief Create a CeedElemRestriction with orientation sign
378 
379   @param ceed         A Ceed object where the CeedElemRestriction will be created
380   @param num_elem     Number of elements described in the @a offsets array
381   @param elem_size    Size (number of "nodes") per element
382   @param num_comp     Number of field components per interpolation node
383                         (1 for scalar fields)
384   @param comp_stride  Stride between components for the same L-vector "node".
385                         Data for node i, component j, element k can be found in
386                         the L-vector at index
387                         offsets[i + k*elem_size] + j*comp_stride.
388   @param l_size       The size of the L-vector. This vector may be larger than
389                         the elements and fields given by this restriction.
390   @param mem_type     Memory type of the @a offsets array, see CeedMemType
391   @param copy_mode    Copy mode for the @a offsets array, see CeedCopyMode
392   @param offsets      Array of shape [@a num_elem, @a elem_size]. Row i holds the
393                         ordered list of the offsets (into the input CeedVector)
394                         for the unknowns corresponding to element i, where
395                         0 <= i < @a num_elem. All offsets must be in the range
396                         [0, @a l_size - 1].
397   @param orient       Array of shape [@a num_elem, @a elem_size] with bool false
398                         for positively oriented and true to flip the orientation.
399   @param[out] rstr    Address of the variable where the newly created
400                         CeedElemRestriction will be stored
401 
402   @return An error code: 0 - success, otherwise - failure
403 
404   @ref User
405 **/
406 int CeedElemRestrictionCreateOriented(Ceed ceed, CeedInt num_elem,
407                                       CeedInt elem_size, CeedInt num_comp,
408                                       CeedInt comp_stride, CeedInt l_size,
409                                       CeedMemType mem_type, CeedCopyMode copy_mode,
410                                       const CeedInt *offsets, const bool *orient,
411                                       CeedElemRestriction *rstr) {
412   int ierr;
413 
414   if (!ceed->ElemRestrictionCreateOriented) {
415     Ceed delegate;
416     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
417     CeedChk(ierr);
418 
419     if (!delegate)
420       // LCOV_EXCL_START
421       return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
422                        "Backend does not implement ElemRestrictionCreateOriented");
423     // LCOV_EXCL_STOP
424 
425     ierr = CeedElemRestrictionCreateOriented(delegate, num_elem, elem_size,
426            num_comp, comp_stride, l_size, mem_type, copy_mode, offsets,
427            orient, rstr); CeedChk(ierr);
428     return CEED_ERROR_SUCCESS;
429   }
430 
431   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
432   (*rstr)->ceed = ceed;
433   ierr = CeedReference(ceed); CeedChk(ierr);
434   (*rstr)->ref_count = 1;
435   (*rstr)->num_elem = num_elem;
436   (*rstr)->elem_size = elem_size;
437   (*rstr)->num_comp = num_comp;
438   (*rstr)->comp_stride = comp_stride;
439   (*rstr)->l_size = l_size;
440   (*rstr)->num_blk = num_elem;
441   (*rstr)->blk_size = 1;
442   (*rstr)->is_oriented = 1;
443   ierr = ceed->ElemRestrictionCreateOriented(mem_type, copy_mode,
444          offsets, orient, *rstr); CeedChk(ierr);
445   return CEED_ERROR_SUCCESS;
446 }
447 
448 /**
449   @brief Create a strided CeedElemRestriction
450 
451   @param ceed       A Ceed object where the CeedElemRestriction will be created
452   @param num_elem   Number of elements described by the restriction
453   @param elem_size  Size (number of "nodes") per element
454   @param num_comp   Number of field components per interpolation "node"
455                       (1 for scalar fields)
456   @param l_size     The size of the L-vector. This vector may be larger than
457                       the elements and fields given by this restriction.
458   @param strides    Array for strides between [nodes, components, elements].
459                       Data for node i, component j, element k can be found in
460                       the L-vector at index
461                       i*strides[0] + j*strides[1] + k*strides[2].
462                       @a CEED_STRIDES_BACKEND may be used with vectors created
463                       by a Ceed backend.
464   @param rstr       Address of the variable where the newly created
465                       CeedElemRestriction will be stored
466 
467   @return An error code: 0 - success, otherwise - failure
468 
469   @ref User
470 **/
471 int CeedElemRestrictionCreateStrided(Ceed ceed, CeedInt num_elem,
472                                      CeedInt elem_size,
473                                      CeedInt num_comp, CeedInt l_size,
474                                      const CeedInt strides[3],
475                                      CeedElemRestriction *rstr) {
476   int ierr;
477 
478   if (!ceed->ElemRestrictionCreate) {
479     Ceed delegate;
480     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
481     CeedChk(ierr);
482 
483     if (!delegate)
484       // LCOV_EXCL_START
485       return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
486                        "Backend does not support ElemRestrictionCreate");
487     // LCOV_EXCL_STOP
488 
489     ierr = CeedElemRestrictionCreateStrided(delegate, num_elem, elem_size, num_comp,
490                                             l_size, strides, rstr);
491     CeedChk(ierr);
492     return CEED_ERROR_SUCCESS;
493   }
494 
495   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
496   (*rstr)->ceed = ceed;
497   ierr = CeedReference(ceed); CeedChk(ierr);
498   (*rstr)->ref_count = 1;
499   (*rstr)->num_elem = num_elem;
500   (*rstr)->elem_size = elem_size;
501   (*rstr)->num_comp = num_comp;
502   (*rstr)->l_size = l_size;
503   (*rstr)->num_blk = num_elem;
504   (*rstr)->blk_size = 1;
505   (*rstr)->is_oriented = 0;
506   ierr = CeedMalloc(3, &(*rstr)->strides); CeedChk(ierr);
507   for (int i=0; i<3; i++)
508     (*rstr)->strides[i] = strides[i];
509   ierr = ceed->ElemRestrictionCreate(CEED_MEM_HOST, CEED_OWN_POINTER, NULL,
510                                      *rstr);
511   CeedChk(ierr);
512   return CEED_ERROR_SUCCESS;
513 }
514 
515 /**
516   @brief Create a blocked CeedElemRestriction, typically only called by backends
517 
518   @param ceed         A Ceed object where the CeedElemRestriction will be created.
519   @param num_elem     Number of elements described in the @a offsets array.
520   @param elem_size    Size (number of unknowns) per element
521   @param blk_size     Number of elements in a block
522   @param num_comp     Number of field components per interpolation node
523                         (1 for scalar fields)
524   @param comp_stride  Stride between components for the same L-vector "node".
525                         Data for node i, component j, element k can be found in
526                         the L-vector at index
527                         offsets[i + k*elem_size] + j*comp_stride.
528   @param l_size       The size of the L-vector. This vector may be larger than
529                         the elements and fields given by this restriction.
530   @param mem_type     Memory type of the @a offsets array, see CeedMemType
531   @param copy_mode    Copy mode for the @a offsets array, see CeedCopyMode
532   @param offsets      Array of shape [@a num_elem, @a elem_size]. Row i holds the
533                         ordered list of the offsets (into the input CeedVector)
534                         for the unknowns corresponding to element i, where
535                         0 <= i < @a num_elem. All offsets must be in the range
536                         [0, @a l_size - 1]. The backend will permute and pad this
537                         array to the desired ordering for the blocksize, which is
538                         typically given by the backend. The default reordering is
539                         to interlace elements.
540   @param rstr         Address of the variable where the newly created
541                         CeedElemRestriction will be stored
542 
543   @return An error code: 0 - success, otherwise - failure
544 
545   @ref Backend
546  **/
547 int CeedElemRestrictionCreateBlocked(Ceed ceed, CeedInt num_elem,
548                                      CeedInt elem_size,
549                                      CeedInt blk_size, CeedInt num_comp,
550                                      CeedInt comp_stride, CeedInt l_size,
551                                      CeedMemType mem_type, CeedCopyMode copy_mode,
552                                      const CeedInt *offsets,
553                                      CeedElemRestriction *rstr) {
554   int ierr;
555   CeedInt *blk_offsets;
556   CeedInt num_blk = (num_elem / blk_size) + !!(num_elem % blk_size);
557 
558   if (!ceed->ElemRestrictionCreateBlocked) {
559     Ceed delegate;
560     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
561     CeedChk(ierr);
562 
563     if (!delegate)
564       // LCOV_EXCL_START
565       return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support "
566                        "ElemRestrictionCreateBlocked");
567     // LCOV_EXCL_STOP
568 
569     ierr = CeedElemRestrictionCreateBlocked(delegate, num_elem, elem_size, blk_size,
570                                             num_comp, comp_stride, l_size, mem_type,
571                                             copy_mode, offsets, rstr);
572     CeedChk(ierr);
573     return CEED_ERROR_SUCCESS;
574   }
575 
576   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
577 
578   ierr = CeedCalloc(num_blk*blk_size*elem_size, &blk_offsets); CeedChk(ierr);
579   ierr = CeedPermutePadOffsets(offsets, blk_offsets, num_blk, num_elem, blk_size,
580                                elem_size); CeedChk(ierr);
581 
582   (*rstr)->ceed = ceed;
583   ierr = CeedReference(ceed); CeedChk(ierr);
584   (*rstr)->ref_count = 1;
585   (*rstr)->num_elem = num_elem;
586   (*rstr)->elem_size = elem_size;
587   (*rstr)->num_comp = num_comp;
588   (*rstr)->comp_stride = comp_stride;
589   (*rstr)->l_size = l_size;
590   (*rstr)->num_blk = num_blk;
591   (*rstr)->blk_size = blk_size;
592   (*rstr)->is_oriented = 0;
593   ierr = ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER,
594          (const CeedInt *) blk_offsets, *rstr); CeedChk(ierr);
595   if (copy_mode == CEED_OWN_POINTER) {
596     ierr = CeedFree(&offsets); CeedChk(ierr);
597   }
598   return CEED_ERROR_SUCCESS;
599 }
600 
601 /**
602   @brief Create a blocked strided CeedElemRestriction
603 
604   @param ceed       A Ceed object where the CeedElemRestriction will be created
605   @param num_elem   Number of elements described by the restriction
606   @param elem_size  Size (number of "nodes") per element
607   @param blk_size   Number of elements in a block
608   @param num_comp   Number of field components per interpolation node
609                       (1 for scalar fields)
610   @param l_size     The size of the L-vector. This vector may be larger than
611                       the elements and fields given by this restriction.
612   @param strides    Array for strides between [nodes, components, elements].
613                       Data for node i, component j, element k can be found in
614                       the L-vector at index
615                       i*strides[0] + j*strides[1] + k*strides[2].
616                       @a CEED_STRIDES_BACKEND may be used with vectors created
617                       by a Ceed backend.
618   @param rstr       Address of the variable where the newly created
619                       CeedElemRestriction will be stored
620 
621   @return An error code: 0 - success, otherwise - failure
622 
623   @ref User
624 **/
625 int CeedElemRestrictionCreateBlockedStrided(Ceed ceed, CeedInt num_elem,
626     CeedInt elem_size, CeedInt blk_size, CeedInt num_comp, CeedInt l_size,
627     const CeedInt strides[3], CeedElemRestriction *rstr) {
628   int ierr;
629   CeedInt num_blk = (num_elem / blk_size) + !!(num_elem % blk_size);
630 
631   if (!ceed->ElemRestrictionCreateBlocked) {
632     Ceed delegate;
633     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
634     CeedChk(ierr);
635 
636     if (!delegate)
637       // LCOV_EXCL_START
638       return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support "
639                        "ElemRestrictionCreateBlocked");
640     // LCOV_EXCL_STOP
641 
642     ierr = CeedElemRestrictionCreateBlockedStrided(delegate, num_elem, elem_size,
643            blk_size, num_comp, l_size, strides, rstr); CeedChk(ierr);
644     return CEED_ERROR_SUCCESS;
645   }
646 
647   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
648 
649   (*rstr)->ceed = ceed;
650   ierr = CeedReference(ceed); CeedChk(ierr);
651   (*rstr)->ref_count = 1;
652   (*rstr)->num_elem = num_elem;
653   (*rstr)->elem_size = elem_size;
654   (*rstr)->num_comp = num_comp;
655   (*rstr)->l_size = l_size;
656   (*rstr)->num_blk = num_blk;
657   (*rstr)->blk_size = blk_size;
658   (*rstr)->is_oriented = 0;
659   ierr = CeedMalloc(3, &(*rstr)->strides); CeedChk(ierr);
660   for (int i=0; i<3; i++)
661     (*rstr)->strides[i] = strides[i];
662   ierr = ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER,
663          NULL, *rstr); CeedChk(ierr);
664   return CEED_ERROR_SUCCESS;
665 }
666 
667 /**
668   @brief Copy the pointer to a CeedElemRestriction. Both pointers should
669            be destroyed with `CeedElemRestrictionDestroy()`;
670            Note: If `*rstr_copy` is non-NULL, then it is assumed that
671            `*rstr_copy` is a pointer to a CeedElemRestriction. This
672            CeedElemRestriction will be destroyed if `*rstr_copy` is the
673            only reference to this CeedElemRestriction.
674 
675   @param rstr            CeedElemRestriction to copy reference to
676   @param[out] rstr_copy  Variable to store copied reference
677 
678   @return An error code: 0 - success, otherwise - failure
679 
680   @ref User
681 **/
682 int CeedElemRestrictionReferenceCopy(CeedElemRestriction rstr,
683                                      CeedElemRestriction *rstr_copy) {
684   int ierr;
685 
686   ierr = CeedElemRestrictionReference(rstr); CeedChk(ierr);
687   ierr = CeedElemRestrictionDestroy(rstr_copy); CeedChk(ierr);
688   *rstr_copy = rstr;
689   return CEED_ERROR_SUCCESS;
690 }
691 
692 /**
693   @brief Create CeedVectors associated with a CeedElemRestriction
694 
695   @param rstr   CeedElemRestriction
696   @param l_vec  The address of the L-vector to be created, or NULL
697   @param e_vec  The address of the E-vector to be created, or NULL
698 
699   @return An error code: 0 - success, otherwise - failure
700 
701   @ref User
702 **/
703 int CeedElemRestrictionCreateVector(CeedElemRestriction rstr, CeedVector *l_vec,
704                                     CeedVector *e_vec) {
705   int ierr;
706   CeedInt e_size, l_size;
707   l_size = rstr->l_size;
708   e_size = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp;
709   if (l_vec) {
710     ierr = CeedVectorCreate(rstr->ceed, l_size, l_vec); CeedChk(ierr);
711   }
712   if (e_vec) {
713     ierr = CeedVectorCreate(rstr->ceed, e_size, e_vec); CeedChk(ierr);
714   }
715   return CEED_ERROR_SUCCESS;
716 }
717 
718 /**
719   @brief Restrict an L-vector to an E-vector or apply its transpose
720 
721   @param rstr    CeedElemRestriction
722   @param t_mode  Apply restriction or transpose
723   @param u       Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE)
724   @param ru      Output vector (of shape [@a num_elem * @a elem_size] when
725                    t_mode=@ref CEED_NOTRANSPOSE). Ordering of the e-vector is decided
726                    by the backend.
727   @param request Request or @ref CEED_REQUEST_IMMEDIATE
728 
729   @return An error code: 0 - success, otherwise - failure
730 
731   @ref User
732 **/
733 int CeedElemRestrictionApply(CeedElemRestriction rstr, CeedTransposeMode t_mode,
734                              CeedVector u, CeedVector ru,
735                              CeedRequest *request) {
736   CeedInt m, n;
737   int ierr;
738 
739   if (t_mode == CEED_NOTRANSPOSE) {
740     m = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp;
741     n = rstr->l_size;
742   } else {
743     m = rstr->l_size;
744     n = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp;
745   }
746   if (n != u->length)
747     // LCOV_EXCL_START
748     return CeedError(rstr->ceed, CEED_ERROR_DIMENSION,
749                      "Input vector size %d not compatible with "
750                      "element restriction (%d, %d)", u->length, m, n);
751   // LCOV_EXCL_STOP
752   if (m != ru->length)
753     // LCOV_EXCL_START
754     return CeedError(rstr->ceed, CEED_ERROR_DIMENSION,
755                      "Output vector size %d not compatible with "
756                      "element restriction (%d, %d)", ru->length, m, n);
757   // LCOV_EXCL_STOP
758   ierr = rstr->Apply(rstr, t_mode, u, ru, request); CeedChk(ierr);
759   return CEED_ERROR_SUCCESS;
760 }
761 
762 /**
763   @brief Restrict an L-vector to a block of an E-vector or apply its transpose
764 
765   @param rstr    CeedElemRestriction
766   @param block   Block number to restrict to/from, i.e. block=0 will handle
767                    elements [0 : blk_size] and block=3 will handle elements
768                    [3*blk_size : 4*blk_size]
769   @param t_mode  Apply restriction or transpose
770   @param u       Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE)
771   @param ru      Output vector (of shape [@a blk_size * @a elem_size] when
772                    t_mode=@ref CEED_NOTRANSPOSE). Ordering of the e-vector is decided
773                    by the backend.
774   @param request Request or @ref CEED_REQUEST_IMMEDIATE
775 
776   @return An error code: 0 - success, otherwise - failure
777 
778   @ref Backend
779 **/
780 int CeedElemRestrictionApplyBlock(CeedElemRestriction rstr, CeedInt block,
781                                   CeedTransposeMode t_mode, CeedVector u,
782                                   CeedVector ru, CeedRequest *request) {
783   CeedInt m, n;
784   int ierr;
785 
786   if (t_mode == CEED_NOTRANSPOSE) {
787     m = rstr->blk_size * rstr->elem_size * rstr->num_comp;
788     n = rstr->l_size;
789   } else {
790     m = rstr->l_size;
791     n = rstr->blk_size * rstr->elem_size * rstr->num_comp;
792   }
793   if (n != u->length)
794     // LCOV_EXCL_START
795     return CeedError(rstr->ceed, CEED_ERROR_DIMENSION,
796                      "Input vector size %d not compatible with "
797                      "element restriction (%d, %d)", u->length, m, n);
798   // LCOV_EXCL_STOP
799   if (m != ru->length)
800     // LCOV_EXCL_START
801     return CeedError(rstr->ceed, CEED_ERROR_DIMENSION,
802                      "Output vector size %d not compatible with "
803                      "element restriction (%d, %d)", ru->length, m, n);
804   // LCOV_EXCL_STOP
805   if (rstr->blk_size*block > rstr->num_elem)
806     // LCOV_EXCL_START
807     return CeedError(rstr->ceed, CEED_ERROR_DIMENSION,
808                      "Cannot retrieve block %d, element %d > "
809                      "total elements %d", block, rstr->blk_size*block,
810                      rstr->num_elem);
811   // LCOV_EXCL_STOP
812   ierr = rstr->ApplyBlock(rstr, block, t_mode, u, ru, request);
813   CeedChk(ierr);
814   return CEED_ERROR_SUCCESS;
815 }
816 
817 /**
818   @brief Get the Ceed associated with a CeedElemRestriction
819 
820   @param rstr       CeedElemRestriction
821   @param[out] ceed  Variable to store Ceed
822 
823   @return An error code: 0 - success, otherwise - failure
824 
825   @ref Advanced
826 **/
827 int CeedElemRestrictionGetCeed(CeedElemRestriction rstr, Ceed *ceed) {
828   *ceed = rstr->ceed;
829   return CEED_ERROR_SUCCESS;
830 }
831 
832 /**
833   @brief Get the L-vector component stride
834 
835   @param rstr              CeedElemRestriction
836   @param[out] comp_stride  Variable to store component stride
837 
838   @return An error code: 0 - success, otherwise - failure
839 
840   @ref Advanced
841 **/
842 int CeedElemRestrictionGetCompStride(CeedElemRestriction rstr,
843                                      CeedInt *comp_stride) {
844   *comp_stride = rstr->comp_stride;
845   return CEED_ERROR_SUCCESS;
846 }
847 
848 /**
849   @brief Get the total number of elements in the range of a CeedElemRestriction
850 
851   @param rstr           CeedElemRestriction
852   @param[out] num_elem  Variable to store number of elements
853 
854   @return An error code: 0 - success, otherwise - failure
855 
856   @ref Advanced
857 **/
858 int CeedElemRestrictionGetNumElements(CeedElemRestriction rstr,
859                                       CeedInt *num_elem) {
860   *num_elem = rstr->num_elem;
861   return CEED_ERROR_SUCCESS;
862 }
863 
864 /**
865   @brief Get the size of elements in the CeedElemRestriction
866 
867   @param rstr            CeedElemRestriction
868   @param[out] elem_size  Variable to store size of elements
869 
870   @return An error code: 0 - success, otherwise - failure
871 
872   @ref Advanced
873 **/
874 int CeedElemRestrictionGetElementSize(CeedElemRestriction rstr,
875                                       CeedInt *elem_size) {
876   *elem_size = rstr->elem_size;
877   return CEED_ERROR_SUCCESS;
878 }
879 
880 /**
881   @brief Get the size of the l-vector for a CeedElemRestriction
882 
883   @param rstr         CeedElemRestriction
884   @param[out] l_size  Variable to store number of nodes
885 
886   @return An error code: 0 - success, otherwise - failure
887 
888   @ref Advanced
889 **/
890 int CeedElemRestrictionGetLVectorSize(CeedElemRestriction rstr,
891                                       CeedInt *l_size) {
892   *l_size = rstr->l_size;
893   return CEED_ERROR_SUCCESS;
894 }
895 
896 /**
897   @brief Get the number of components in the elements of a
898          CeedElemRestriction
899 
900   @param rstr           CeedElemRestriction
901   @param[out] num_comp  Variable to store number of components
902 
903   @return An error code: 0 - success, otherwise - failure
904 
905   @ref Advanced
906 **/
907 int CeedElemRestrictionGetNumComponents(CeedElemRestriction rstr,
908                                         CeedInt *num_comp) {
909   *num_comp = rstr->num_comp;
910   return CEED_ERROR_SUCCESS;
911 }
912 
913 /**
914   @brief Get the number of blocks in a CeedElemRestriction
915 
916   @param rstr            CeedElemRestriction
917   @param[out] num_block  Variable to store number of blocks
918 
919   @return An error code: 0 - success, otherwise - failure
920 
921   @ref Advanced
922 **/
923 int CeedElemRestrictionGetNumBlocks(CeedElemRestriction rstr,
924                                     CeedInt *num_block) {
925   *num_block = rstr->num_blk;
926   return CEED_ERROR_SUCCESS;
927 }
928 
929 /**
930   @brief Get the size of blocks in the CeedElemRestriction
931 
932   @param rstr           CeedElemRestriction
933   @param[out] blk_size  Variable to store size of blocks
934 
935   @return An error code: 0 - success, otherwise - failure
936 
937   @ref Advanced
938 **/
939 int CeedElemRestrictionGetBlockSize(CeedElemRestriction rstr,
940                                     CeedInt *blk_size) {
941   *blk_size = rstr->blk_size;
942   return CEED_ERROR_SUCCESS;
943 }
944 
945 /**
946   @brief Get the multiplicity of nodes in a CeedElemRestriction
947 
948   @param rstr       CeedElemRestriction
949   @param[out] mult  Vector to store multiplicity (of size l_size)
950 
951   @return An error code: 0 - success, otherwise - failure
952 
953   @ref User
954 **/
955 int CeedElemRestrictionGetMultiplicity(CeedElemRestriction rstr,
956                                        CeedVector mult) {
957   int ierr;
958   CeedVector e_vec;
959 
960   // Create e_vec to hold intermediate computation in E^T (E 1)
961   ierr = CeedElemRestrictionCreateVector(rstr, NULL, &e_vec); CeedChk(ierr);
962 
963   // Compute e_vec = E * 1
964   ierr = CeedVectorSetValue(mult, 1.0); CeedChk(ierr);
965   ierr = CeedElemRestrictionApply(rstr, CEED_NOTRANSPOSE, mult, e_vec,
966                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
967   // Compute multiplicity, mult = E^T * e_vec = E^T (E 1)
968   ierr = CeedVectorSetValue(mult, 0.0); CeedChk(ierr);
969   ierr = CeedElemRestrictionApply(rstr, CEED_TRANSPOSE, e_vec, mult,
970                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
971   // Cleanup
972   ierr = CeedVectorDestroy(&e_vec); CeedChk(ierr);
973   return CEED_ERROR_SUCCESS;
974 }
975 
976 /**
977   @brief View a CeedElemRestriction
978 
979   @param[in] rstr    CeedElemRestriction to view
980   @param[in] stream  Stream to write; typically stdout/stderr or a file
981 
982   @return Error code: 0 - success, otherwise - failure
983 
984   @ref User
985 **/
986 int CeedElemRestrictionView(CeedElemRestriction rstr, FILE *stream) {
987   char stridesstr[500];
988   if (rstr->strides)
989     sprintf(stridesstr, "[%d, %d, %d]", rstr->strides[0], rstr->strides[1],
990             rstr->strides[2]);
991   else
992     sprintf(stridesstr, "%d", rstr->comp_stride);
993 
994   fprintf(stream, "%sCeedElemRestriction from (%d, %d) to %d elements with %d "
995           "nodes each and %s %s\n", rstr->blk_size > 1 ? "Blocked " : "",
996           rstr->l_size, rstr->num_comp, rstr->num_elem, rstr->elem_size,
997           rstr->strides ? "strides" : "component stride", stridesstr);
998   return CEED_ERROR_SUCCESS;
999 }
1000 
1001 /**
1002   @brief Destroy a CeedElemRestriction
1003 
1004   @param rstr  CeedElemRestriction to destroy
1005 
1006   @return An error code: 0 - success, otherwise - failure
1007 
1008   @ref User
1009 **/
1010 int CeedElemRestrictionDestroy(CeedElemRestriction *rstr) {
1011   int ierr;
1012 
1013   if (!*rstr || --(*rstr)->ref_count > 0) return CEED_ERROR_SUCCESS;
1014   if ((*rstr)->num_readers)
1015     // LCOV_EXCL_START
1016     return CeedError((*rstr)->ceed, CEED_ERROR_ACCESS,
1017                      "Cannot destroy CeedElemRestriction, "
1018                      "a process has read access to the offset data");
1019   // LCOV_EXCL_STOP
1020   if ((*rstr)->Destroy) {
1021     ierr = (*rstr)->Destroy(*rstr); CeedChk(ierr);
1022   }
1023   ierr = CeedFree(&(*rstr)->strides); CeedChk(ierr);
1024   ierr = CeedDestroy(&(*rstr)->ceed); CeedChk(ierr);
1025   ierr = CeedFree(rstr); CeedChk(ierr);
1026   return CEED_ERROR_SUCCESS;
1027 }
1028 
1029 /// @}
1030