xref: /libCEED/interface/ceed-elemrestriction.c (revision ea6b58218a3c4883c2efd66165b4d6b684f89f5a)
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 (int j=0; j<blk_size; j++)
47       for (int 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 (int 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 (int 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 (int 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   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
378   (*rstr)->ceed = ceed;
379   ierr = CeedReference(ceed); CeedChk(ierr);
380   (*rstr)->ref_count = 1;
381   (*rstr)->num_elem = num_elem;
382   (*rstr)->elem_size = elem_size;
383   (*rstr)->num_comp = num_comp;
384   (*rstr)->comp_stride = comp_stride;
385   (*rstr)->l_size = l_size;
386   (*rstr)->num_blk = num_elem;
387   (*rstr)->blk_size = 1;
388   (*rstr)->is_oriented = 0;
389   ierr = ceed->ElemRestrictionCreate(mem_type, copy_mode, offsets, *rstr);
390   CeedChk(ierr);
391   return CEED_ERROR_SUCCESS;
392 }
393 
394 /**
395   @brief Create a CeedElemRestriction with orientation sign
396 
397   @param ceed         A Ceed object where the CeedElemRestriction will be created
398   @param num_elem     Number of elements described in the @a offsets array
399   @param elem_size    Size (number of "nodes") per element
400   @param num_comp     Number of field components per interpolation node
401                         (1 for scalar fields)
402   @param comp_stride  Stride between components for the same L-vector "node".
403                         Data for node i, component j, element k can be found in
404                         the L-vector at index
405                         offsets[i + k*elem_size] + j*comp_stride.
406   @param l_size       The size of the L-vector. This vector may be larger than
407                         the elements and fields given by this restriction.
408   @param mem_type     Memory type of the @a offsets array, see CeedMemType
409   @param copy_mode    Copy mode for the @a offsets array, see CeedCopyMode
410   @param offsets      Array of shape [@a num_elem, @a elem_size]. Row i holds the
411                         ordered list of the offsets (into the input CeedVector)
412                         for the unknowns corresponding to element i, where
413                         0 <= i < @a num_elem. All offsets must be in the range
414                         [0, @a l_size - 1].
415   @param orient       Array of shape [@a num_elem, @a elem_size] with bool false
416                         for positively oriented and true to flip the orientation.
417   @param[out] rstr    Address of the variable where the newly created
418                         CeedElemRestriction will be stored
419 
420   @return An error code: 0 - success, otherwise - failure
421 
422   @ref User
423 **/
424 int CeedElemRestrictionCreateOriented(Ceed ceed, CeedInt num_elem,
425                                       CeedInt elem_size, CeedInt num_comp,
426                                       CeedInt comp_stride, CeedSize l_size,
427                                       CeedMemType mem_type, CeedCopyMode copy_mode,
428                                       const CeedInt *offsets, const bool *orient,
429                                       CeedElemRestriction *rstr) {
430   int ierr;
431 
432   if (!ceed->ElemRestrictionCreateOriented) {
433     Ceed delegate;
434     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
435     CeedChk(ierr);
436 
437     if (!delegate)
438       // LCOV_EXCL_START
439       return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
440                        "Backend does not implement ElemRestrictionCreateOriented");
441     // LCOV_EXCL_STOP
442 
443     ierr = CeedElemRestrictionCreateOriented(delegate, num_elem, elem_size,
444            num_comp, comp_stride, l_size, mem_type, copy_mode, offsets,
445            orient, rstr); CeedChk(ierr);
446     return CEED_ERROR_SUCCESS;
447   }
448 
449   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
450   (*rstr)->ceed = ceed;
451   ierr = CeedReference(ceed); CeedChk(ierr);
452   (*rstr)->ref_count = 1;
453   (*rstr)->num_elem = num_elem;
454   (*rstr)->elem_size = elem_size;
455   (*rstr)->num_comp = num_comp;
456   (*rstr)->comp_stride = comp_stride;
457   (*rstr)->l_size = l_size;
458   (*rstr)->num_blk = num_elem;
459   (*rstr)->blk_size = 1;
460   (*rstr)->is_oriented = 1;
461   ierr = ceed->ElemRestrictionCreateOriented(mem_type, copy_mode,
462          offsets, orient, *rstr); CeedChk(ierr);
463   return CEED_ERROR_SUCCESS;
464 }
465 
466 /**
467   @brief Create a strided CeedElemRestriction
468 
469   @param ceed       A Ceed object where the CeedElemRestriction will be created
470   @param num_elem   Number of elements described by the restriction
471   @param elem_size  Size (number of "nodes") per element
472   @param num_comp   Number of field components per interpolation "node"
473                       (1 for scalar fields)
474   @param l_size     The size of the L-vector. This vector may be larger than
475                       the elements and fields given by this restriction.
476   @param strides    Array for strides between [nodes, components, elements].
477                       Data for node i, component j, element k can be found in
478                       the L-vector at index
479                       i*strides[0] + j*strides[1] + k*strides[2].
480                       @a CEED_STRIDES_BACKEND may be used with vectors created
481                       by a Ceed backend.
482   @param rstr       Address of the variable where the newly created
483                       CeedElemRestriction will be stored
484 
485   @return An error code: 0 - success, otherwise - failure
486 
487   @ref User
488 **/
489 int CeedElemRestrictionCreateStrided(Ceed ceed, CeedInt num_elem,
490                                      CeedInt elem_size,
491                                      CeedInt num_comp, CeedSize l_size,
492                                      const CeedInt strides[3],
493                                      CeedElemRestriction *rstr) {
494   int ierr;
495 
496   if (!ceed->ElemRestrictionCreate) {
497     Ceed delegate;
498     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
499     CeedChk(ierr);
500 
501     if (!delegate)
502       // LCOV_EXCL_START
503       return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
504                        "Backend does not support ElemRestrictionCreate");
505     // LCOV_EXCL_STOP
506 
507     ierr = CeedElemRestrictionCreateStrided(delegate, num_elem, elem_size, num_comp,
508                                             l_size, strides, rstr);
509     CeedChk(ierr);
510     return CEED_ERROR_SUCCESS;
511   }
512 
513   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
514   (*rstr)->ceed = ceed;
515   ierr = CeedReference(ceed); CeedChk(ierr);
516   (*rstr)->ref_count = 1;
517   (*rstr)->num_elem = num_elem;
518   (*rstr)->elem_size = elem_size;
519   (*rstr)->num_comp = num_comp;
520   (*rstr)->l_size = l_size;
521   (*rstr)->num_blk = num_elem;
522   (*rstr)->blk_size = 1;
523   (*rstr)->is_oriented = 0;
524   ierr = CeedMalloc(3, &(*rstr)->strides); CeedChk(ierr);
525   for (int i=0; i<3; i++)
526     (*rstr)->strides[i] = strides[i];
527   ierr = ceed->ElemRestrictionCreate(CEED_MEM_HOST, CEED_OWN_POINTER, NULL,
528                                      *rstr);
529   CeedChk(ierr);
530   return CEED_ERROR_SUCCESS;
531 }
532 
533 /**
534   @brief Create a blocked CeedElemRestriction, typically only called by backends
535 
536   @param ceed         A Ceed object where the CeedElemRestriction will be created.
537   @param num_elem     Number of elements described in the @a offsets array.
538   @param elem_size    Size (number of unknowns) per element
539   @param blk_size     Number of elements in a block
540   @param num_comp     Number of field components per interpolation node
541                         (1 for scalar fields)
542   @param comp_stride  Stride between components for the same L-vector "node".
543                         Data for node i, component j, element k can be found in
544                         the L-vector at index
545                         offsets[i + k*elem_size] + j*comp_stride.
546   @param l_size       The size of the L-vector. This vector may be larger than
547                         the elements and fields given by this restriction.
548   @param mem_type     Memory type of the @a offsets array, see CeedMemType
549   @param copy_mode    Copy mode for the @a offsets array, see CeedCopyMode
550   @param offsets      Array of shape [@a num_elem, @a elem_size]. Row i holds the
551                         ordered list of the offsets (into the input CeedVector)
552                         for the unknowns corresponding to element i, where
553                         0 <= i < @a num_elem. All offsets must be in the range
554                         [0, @a l_size - 1]. The backend will permute and pad this
555                         array to the desired ordering for the blocksize, which is
556                         typically given by the backend. The default reordering is
557                         to interlace elements.
558   @param rstr         Address of the variable where the newly created
559                         CeedElemRestriction will be stored
560 
561   @return An error code: 0 - success, otherwise - failure
562 
563   @ref Backend
564  **/
565 int CeedElemRestrictionCreateBlocked(Ceed ceed, CeedInt num_elem,
566                                      CeedInt elem_size,
567                                      CeedInt blk_size, CeedInt num_comp,
568                                      CeedInt comp_stride, CeedSize l_size,
569                                      CeedMemType mem_type, CeedCopyMode copy_mode,
570                                      const CeedInt *offsets,
571                                      CeedElemRestriction *rstr) {
572   int ierr;
573   CeedInt *blk_offsets;
574   CeedInt num_blk = (num_elem / blk_size) + !!(num_elem % blk_size);
575 
576   if (!ceed->ElemRestrictionCreateBlocked) {
577     Ceed delegate;
578     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
579     CeedChk(ierr);
580 
581     if (!delegate)
582       // LCOV_EXCL_START
583       return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support "
584                        "ElemRestrictionCreateBlocked");
585     // LCOV_EXCL_STOP
586 
587     ierr = CeedElemRestrictionCreateBlocked(delegate, num_elem, elem_size, blk_size,
588                                             num_comp, comp_stride, l_size, mem_type,
589                                             copy_mode, offsets, rstr);
590     CeedChk(ierr);
591     return CEED_ERROR_SUCCESS;
592   }
593 
594   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
595 
596   ierr = CeedCalloc(num_blk*blk_size*elem_size, &blk_offsets); CeedChk(ierr);
597   ierr = CeedPermutePadOffsets(offsets, blk_offsets, num_blk, num_elem, blk_size,
598                                elem_size); CeedChk(ierr);
599 
600   (*rstr)->ceed = ceed;
601   ierr = CeedReference(ceed); CeedChk(ierr);
602   (*rstr)->ref_count = 1;
603   (*rstr)->num_elem = num_elem;
604   (*rstr)->elem_size = elem_size;
605   (*rstr)->num_comp = num_comp;
606   (*rstr)->comp_stride = comp_stride;
607   (*rstr)->l_size = l_size;
608   (*rstr)->num_blk = num_blk;
609   (*rstr)->blk_size = blk_size;
610   (*rstr)->is_oriented = 0;
611   ierr = ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER,
612          (const CeedInt *) blk_offsets, *rstr); CeedChk(ierr);
613   if (copy_mode == CEED_OWN_POINTER) {
614     ierr = CeedFree(&offsets); CeedChk(ierr);
615   }
616   return CEED_ERROR_SUCCESS;
617 }
618 
619 /**
620   @brief Create a blocked strided CeedElemRestriction
621 
622   @param ceed       A Ceed object where the CeedElemRestriction will be created
623   @param num_elem   Number of elements described by the restriction
624   @param elem_size  Size (number of "nodes") per element
625   @param blk_size   Number of elements in a block
626   @param num_comp   Number of field components per interpolation node
627                       (1 for scalar fields)
628   @param l_size     The size of the L-vector. This vector may be larger than
629                       the elements and fields given by this restriction.
630   @param strides    Array for strides between [nodes, components, elements].
631                       Data for node i, component j, element k can be found in
632                       the L-vector at index
633                       i*strides[0] + j*strides[1] + k*strides[2].
634                       @a CEED_STRIDES_BACKEND may be used with vectors created
635                       by a Ceed backend.
636   @param rstr       Address of the variable where the newly created
637                       CeedElemRestriction will be stored
638 
639   @return An error code: 0 - success, otherwise - failure
640 
641   @ref User
642 **/
643 int CeedElemRestrictionCreateBlockedStrided(Ceed ceed, CeedInt num_elem,
644     CeedInt elem_size, CeedInt blk_size, CeedInt num_comp, CeedSize l_size,
645     const CeedInt strides[3], CeedElemRestriction *rstr) {
646   int ierr;
647   CeedInt num_blk = (num_elem / blk_size) + !!(num_elem % blk_size);
648 
649   if (!ceed->ElemRestrictionCreateBlocked) {
650     Ceed delegate;
651     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
652     CeedChk(ierr);
653 
654     if (!delegate)
655       // LCOV_EXCL_START
656       return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support "
657                        "ElemRestrictionCreateBlocked");
658     // LCOV_EXCL_STOP
659 
660     ierr = CeedElemRestrictionCreateBlockedStrided(delegate, num_elem, elem_size,
661            blk_size, num_comp, l_size, strides, rstr); CeedChk(ierr);
662     return CEED_ERROR_SUCCESS;
663   }
664 
665   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
666 
667   (*rstr)->ceed = ceed;
668   ierr = CeedReference(ceed); CeedChk(ierr);
669   (*rstr)->ref_count = 1;
670   (*rstr)->num_elem = num_elem;
671   (*rstr)->elem_size = elem_size;
672   (*rstr)->num_comp = num_comp;
673   (*rstr)->l_size = l_size;
674   (*rstr)->num_blk = num_blk;
675   (*rstr)->blk_size = blk_size;
676   (*rstr)->is_oriented = 0;
677   ierr = CeedMalloc(3, &(*rstr)->strides); CeedChk(ierr);
678   for (int i=0; i<3; i++)
679     (*rstr)->strides[i] = strides[i];
680   ierr = ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER,
681          NULL, *rstr); CeedChk(ierr);
682   return CEED_ERROR_SUCCESS;
683 }
684 
685 /**
686   @brief Copy the pointer to a CeedElemRestriction. Both pointers should
687            be destroyed with `CeedElemRestrictionDestroy()`;
688            Note: If `*rstr_copy` is non-NULL, then it is assumed that
689            `*rstr_copy` is a pointer to a CeedElemRestriction. This
690            CeedElemRestriction will be destroyed if `*rstr_copy` is the
691            only reference to this CeedElemRestriction.
692 
693   @param rstr            CeedElemRestriction to copy reference to
694   @param[out] rstr_copy  Variable to store copied reference
695 
696   @return An error code: 0 - success, otherwise - failure
697 
698   @ref User
699 **/
700 int CeedElemRestrictionReferenceCopy(CeedElemRestriction rstr,
701                                      CeedElemRestriction *rstr_copy) {
702   int ierr;
703 
704   ierr = CeedElemRestrictionReference(rstr); CeedChk(ierr);
705   ierr = CeedElemRestrictionDestroy(rstr_copy); CeedChk(ierr);
706   *rstr_copy = rstr;
707   return CEED_ERROR_SUCCESS;
708 }
709 
710 /**
711   @brief Create CeedVectors associated with a CeedElemRestriction
712 
713   @param rstr   CeedElemRestriction
714   @param l_vec  The address of the L-vector to be created, or NULL
715   @param e_vec  The address of the E-vector to be created, or NULL
716 
717   @return An error code: 0 - success, otherwise - failure
718 
719   @ref User
720 **/
721 int CeedElemRestrictionCreateVector(CeedElemRestriction rstr, CeedVector *l_vec,
722                                     CeedVector *e_vec) {
723   int ierr;
724   CeedSize e_size, l_size;
725   l_size = rstr->l_size;
726   e_size = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp;
727   if (l_vec) {
728     ierr = CeedVectorCreate(rstr->ceed, l_size, l_vec); CeedChk(ierr);
729   }
730   if (e_vec) {
731     ierr = CeedVectorCreate(rstr->ceed, e_size, e_vec); CeedChk(ierr);
732   }
733   return CEED_ERROR_SUCCESS;
734 }
735 
736 /**
737   @brief Restrict an L-vector to an E-vector or apply its transpose
738 
739   @param rstr    CeedElemRestriction
740   @param t_mode  Apply restriction or transpose
741   @param u       Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE)
742   @param ru      Output vector (of shape [@a num_elem * @a elem_size] when
743                    t_mode=@ref CEED_NOTRANSPOSE). Ordering of the e-vector is decided
744                    by the backend.
745   @param request Request or @ref CEED_REQUEST_IMMEDIATE
746 
747   @return An error code: 0 - success, otherwise - failure
748 
749   @ref User
750 **/
751 int CeedElemRestrictionApply(CeedElemRestriction rstr, CeedTransposeMode t_mode,
752                              CeedVector u, CeedVector ru,
753                              CeedRequest *request) {
754   CeedInt m, n;
755   int ierr;
756 
757   if (t_mode == CEED_NOTRANSPOSE) {
758     m = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp;
759     n = rstr->l_size;
760   } else {
761     m = rstr->l_size;
762     n = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp;
763   }
764   if (n != u->length)
765     // LCOV_EXCL_START
766     return CeedError(rstr->ceed, CEED_ERROR_DIMENSION,
767                      "Input vector size %d not compatible with "
768                      "element restriction (%d, %d)", u->length, m, n);
769   // LCOV_EXCL_STOP
770   if (m != ru->length)
771     // LCOV_EXCL_START
772     return CeedError(rstr->ceed, CEED_ERROR_DIMENSION,
773                      "Output vector size %d not compatible with "
774                      "element restriction (%d, %d)", ru->length, m, n);
775   // LCOV_EXCL_STOP
776   ierr = rstr->Apply(rstr, t_mode, u, ru, request); CeedChk(ierr);
777   return CEED_ERROR_SUCCESS;
778 }
779 
780 /**
781   @brief Restrict an L-vector to a block of an E-vector or apply its transpose
782 
783   @param rstr    CeedElemRestriction
784   @param block   Block number to restrict to/from, i.e. block=0 will handle
785                    elements [0 : blk_size] and block=3 will handle elements
786                    [3*blk_size : 4*blk_size]
787   @param t_mode  Apply restriction or transpose
788   @param u       Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE)
789   @param ru      Output vector (of shape [@a blk_size * @a elem_size] when
790                    t_mode=@ref CEED_NOTRANSPOSE). Ordering of the e-vector is decided
791                    by the backend.
792   @param request Request or @ref CEED_REQUEST_IMMEDIATE
793 
794   @return An error code: 0 - success, otherwise - failure
795 
796   @ref Backend
797 **/
798 int CeedElemRestrictionApplyBlock(CeedElemRestriction rstr, CeedInt block,
799                                   CeedTransposeMode t_mode, CeedVector u,
800                                   CeedVector ru, CeedRequest *request) {
801   CeedInt m, n;
802   int ierr;
803 
804   if (t_mode == CEED_NOTRANSPOSE) {
805     m = rstr->blk_size * rstr->elem_size * rstr->num_comp;
806     n = rstr->l_size;
807   } else {
808     m = rstr->l_size;
809     n = rstr->blk_size * rstr->elem_size * rstr->num_comp;
810   }
811   if (n != u->length)
812     // LCOV_EXCL_START
813     return CeedError(rstr->ceed, CEED_ERROR_DIMENSION,
814                      "Input vector size %d not compatible with "
815                      "element restriction (%d, %d)", u->length, m, n);
816   // LCOV_EXCL_STOP
817   if (m != ru->length)
818     // LCOV_EXCL_START
819     return CeedError(rstr->ceed, CEED_ERROR_DIMENSION,
820                      "Output vector size %d not compatible with "
821                      "element restriction (%d, %d)", ru->length, m, n);
822   // LCOV_EXCL_STOP
823   if (rstr->blk_size*block > rstr->num_elem)
824     // LCOV_EXCL_START
825     return CeedError(rstr->ceed, CEED_ERROR_DIMENSION,
826                      "Cannot retrieve block %d, element %d > "
827                      "total elements %d", block, rstr->blk_size*block,
828                      rstr->num_elem);
829   // LCOV_EXCL_STOP
830   ierr = rstr->ApplyBlock(rstr, block, t_mode, u, ru, request);
831   CeedChk(ierr);
832   return CEED_ERROR_SUCCESS;
833 }
834 
835 /**
836   @brief Get the Ceed associated with a CeedElemRestriction
837 
838   @param rstr       CeedElemRestriction
839   @param[out] ceed  Variable to store Ceed
840 
841   @return An error code: 0 - success, otherwise - failure
842 
843   @ref Advanced
844 **/
845 int CeedElemRestrictionGetCeed(CeedElemRestriction rstr, Ceed *ceed) {
846   *ceed = rstr->ceed;
847   return CEED_ERROR_SUCCESS;
848 }
849 
850 /**
851   @brief Get the L-vector component stride
852 
853   @param rstr              CeedElemRestriction
854   @param[out] comp_stride  Variable to store component stride
855 
856   @return An error code: 0 - success, otherwise - failure
857 
858   @ref Advanced
859 **/
860 int CeedElemRestrictionGetCompStride(CeedElemRestriction rstr,
861                                      CeedInt *comp_stride) {
862   *comp_stride = rstr->comp_stride;
863   return CEED_ERROR_SUCCESS;
864 }
865 
866 /**
867   @brief Get the total number of elements in the range of a CeedElemRestriction
868 
869   @param rstr           CeedElemRestriction
870   @param[out] num_elem  Variable to store number of elements
871 
872   @return An error code: 0 - success, otherwise - failure
873 
874   @ref Advanced
875 **/
876 int CeedElemRestrictionGetNumElements(CeedElemRestriction rstr,
877                                       CeedInt *num_elem) {
878   *num_elem = rstr->num_elem;
879   return CEED_ERROR_SUCCESS;
880 }
881 
882 /**
883   @brief Get the size of elements in the CeedElemRestriction
884 
885   @param rstr            CeedElemRestriction
886   @param[out] elem_size  Variable to store size of elements
887 
888   @return An error code: 0 - success, otherwise - failure
889 
890   @ref Advanced
891 **/
892 int CeedElemRestrictionGetElementSize(CeedElemRestriction rstr,
893                                       CeedInt *elem_size) {
894   *elem_size = rstr->elem_size;
895   return CEED_ERROR_SUCCESS;
896 }
897 
898 /**
899   @brief Get the size of the l-vector for a CeedElemRestriction
900 
901   @param rstr         CeedElemRestriction
902   @param[out] l_size  Variable to store number of nodes
903 
904   @return An error code: 0 - success, otherwise - failure
905 
906   @ref Advanced
907 **/
908 int CeedElemRestrictionGetLVectorSize(CeedElemRestriction rstr,
909                                       CeedSize *l_size) {
910   *l_size = rstr->l_size;
911   return CEED_ERROR_SUCCESS;
912 }
913 
914 /**
915   @brief Get the number of components in the elements of a
916          CeedElemRestriction
917 
918   @param rstr           CeedElemRestriction
919   @param[out] num_comp  Variable to store number of components
920 
921   @return An error code: 0 - success, otherwise - failure
922 
923   @ref Advanced
924 **/
925 int CeedElemRestrictionGetNumComponents(CeedElemRestriction rstr,
926                                         CeedInt *num_comp) {
927   *num_comp = rstr->num_comp;
928   return CEED_ERROR_SUCCESS;
929 }
930 
931 /**
932   @brief Get the number of blocks in a CeedElemRestriction
933 
934   @param rstr            CeedElemRestriction
935   @param[out] num_block  Variable to store number of blocks
936 
937   @return An error code: 0 - success, otherwise - failure
938 
939   @ref Advanced
940 **/
941 int CeedElemRestrictionGetNumBlocks(CeedElemRestriction rstr,
942                                     CeedInt *num_block) {
943   *num_block = rstr->num_blk;
944   return CEED_ERROR_SUCCESS;
945 }
946 
947 /**
948   @brief Get the size of blocks in the CeedElemRestriction
949 
950   @param rstr           CeedElemRestriction
951   @param[out] blk_size  Variable to store size of blocks
952 
953   @return An error code: 0 - success, otherwise - failure
954 
955   @ref Advanced
956 **/
957 int CeedElemRestrictionGetBlockSize(CeedElemRestriction rstr,
958                                     CeedInt *blk_size) {
959   *blk_size = rstr->blk_size;
960   return CEED_ERROR_SUCCESS;
961 }
962 
963 /**
964   @brief Get the multiplicity of nodes in a CeedElemRestriction
965 
966   @param rstr       CeedElemRestriction
967   @param[out] mult  Vector to store multiplicity (of size l_size)
968 
969   @return An error code: 0 - success, otherwise - failure
970 
971   @ref User
972 **/
973 int CeedElemRestrictionGetMultiplicity(CeedElemRestriction rstr,
974                                        CeedVector mult) {
975   int ierr;
976   CeedVector e_vec;
977 
978   // Create e_vec to hold intermediate computation in E^T (E 1)
979   ierr = CeedElemRestrictionCreateVector(rstr, NULL, &e_vec); CeedChk(ierr);
980 
981   // Compute e_vec = E * 1
982   ierr = CeedVectorSetValue(mult, 1.0); CeedChk(ierr);
983   ierr = CeedElemRestrictionApply(rstr, CEED_NOTRANSPOSE, mult, e_vec,
984                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
985   // Compute multiplicity, mult = E^T * e_vec = E^T (E 1)
986   ierr = CeedVectorSetValue(mult, 0.0); CeedChk(ierr);
987   ierr = CeedElemRestrictionApply(rstr, CEED_TRANSPOSE, e_vec, mult,
988                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
989   // Cleanup
990   ierr = CeedVectorDestroy(&e_vec); CeedChk(ierr);
991   return CEED_ERROR_SUCCESS;
992 }
993 
994 /**
995   @brief View a CeedElemRestriction
996 
997   @param[in] rstr    CeedElemRestriction to view
998   @param[in] stream  Stream to write; typically stdout/stderr or a file
999 
1000   @return Error code: 0 - success, otherwise - failure
1001 
1002   @ref User
1003 **/
1004 int CeedElemRestrictionView(CeedElemRestriction rstr, FILE *stream) {
1005   char stridesstr[500];
1006   if (rstr->strides)
1007     sprintf(stridesstr, "[%d, %d, %d]", rstr->strides[0], rstr->strides[1],
1008             rstr->strides[2]);
1009   else
1010     sprintf(stridesstr, "%d", rstr->comp_stride);
1011 
1012   fprintf(stream, "%sCeedElemRestriction from (%td, %d) to %d elements with %d "
1013           "nodes each and %s %s\n", rstr->blk_size > 1 ? "Blocked " : "",
1014           rstr->l_size, rstr->num_comp, rstr->num_elem, rstr->elem_size,
1015           rstr->strides ? "strides" : "component stride", stridesstr);
1016   return CEED_ERROR_SUCCESS;
1017 }
1018 
1019 /**
1020   @brief Destroy a CeedElemRestriction
1021 
1022   @param rstr  CeedElemRestriction to destroy
1023 
1024   @return An error code: 0 - success, otherwise - failure
1025 
1026   @ref User
1027 **/
1028 int CeedElemRestrictionDestroy(CeedElemRestriction *rstr) {
1029   int ierr;
1030 
1031   if (!*rstr || --(*rstr)->ref_count > 0) return CEED_ERROR_SUCCESS;
1032   if ((*rstr)->num_readers)
1033     // LCOV_EXCL_START
1034     return CeedError((*rstr)->ceed, CEED_ERROR_ACCESS,
1035                      "Cannot destroy CeedElemRestriction, "
1036                      "a process has read access to the offset data");
1037   // LCOV_EXCL_STOP
1038   if ((*rstr)->Destroy) {
1039     ierr = (*rstr)->Destroy(*rstr); CeedChk(ierr);
1040   }
1041   ierr = CeedFree(&(*rstr)->strides); CeedChk(ierr);
1042   ierr = CeedDestroy(&(*rstr)->ceed); CeedChk(ierr);
1043   ierr = CeedFree(rstr); CeedChk(ierr);
1044   return CEED_ERROR_SUCCESS;
1045 }
1046 
1047 /// @}
1048