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