xref: /libCEED/rust/libceed-sys/c-src/backends/ref/ceed-ref-restriction.c (revision 3bdd4e5a84903d9ef10177c79e65525d59684ccd)
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.h>
9 #include <ceed/backend.h>
10 #include <stdbool.h>
11 #include <string.h>
12 
13 #include "ceed-ref.h"
14 
15 //------------------------------------------------------------------------------
16 // Core ElemRestriction Apply Code
17 //------------------------------------------------------------------------------
18 static inline int CeedElemRestrictionApply_Ref_Core(CeedElemRestriction r, const CeedInt num_comp, const CeedInt blk_size, const CeedInt comp_stride,
19                                                     CeedInt start, CeedInt stop, bool use_orient, CeedTransposeMode t_mode, CeedVector u,
20                                                     CeedVector v, CeedRequest *request) {
21   CeedElemRestriction_Ref *impl;
22   CeedCallBackend(CeedElemRestrictionGetData(r, &impl));
23   const CeedScalar *uu;
24   CeedScalar       *vv;
25   CeedInt           num_elem, elem_size, v_offset;
26   CeedCallBackend(CeedElemRestrictionGetNumElements(r, &num_elem));
27   CeedCallBackend(CeedElemRestrictionGetElementSize(r, &elem_size));
28   v_offset = start * blk_size * elem_size * num_comp;
29 
30   bool is_oriented;
31   CeedCallBackend(CeedElemRestrictionIsOriented(r, &is_oriented));
32   CeedCallBackend(CeedVectorGetArrayRead(u, CEED_MEM_HOST, &uu));
33   if (t_mode == CEED_TRANSPOSE) {
34     // Sum into for transpose mode, e-vec to l-vec
35     CeedCallBackend(CeedVectorGetArray(v, CEED_MEM_HOST, &vv));
36   } else {
37     // Overwrite for notranspose mode, l-vec to e-vec
38     CeedCallBackend(CeedVectorGetArrayWrite(v, CEED_MEM_HOST, &vv));
39   }
40   // Restriction from L-vector to E-vector
41   // Perform: v = r * u
42   if (t_mode == CEED_NOTRANSPOSE) {
43     // No offsets provided, Identity Restriction
44     if (!impl->offsets) {
45       bool has_backend_strides;
46       CeedCallBackend(CeedElemRestrictionHasBackendStrides(r, &has_backend_strides));
47       if (has_backend_strides) {
48         // CPU backend strides are {1, elem_size, elem_size*num_comp}
49         // This if branch is left separate to allow better inlining
50         for (CeedInt e = start * blk_size; e < stop * blk_size; e += blk_size) {
51           CeedPragmaSIMD for (CeedInt k = 0; k < num_comp; k++) {
52             CeedPragmaSIMD for (CeedInt n = 0; n < elem_size; n++) {
53               CeedPragmaSIMD for (CeedInt j = 0; j < blk_size; j++) {
54                 vv[e * elem_size * num_comp + (k * elem_size + n) * blk_size + j - v_offset] =
55                     uu[n + k * elem_size + CeedIntMin(e + j, num_elem - 1) * elem_size * num_comp];
56               }
57             }
58           }
59         }
60       } else {
61         // User provided strides
62         CeedInt strides[3];
63         CeedCallBackend(CeedElemRestrictionGetStrides(r, &strides));
64         for (CeedInt e = start * blk_size; e < stop * blk_size; e += blk_size) {
65           CeedPragmaSIMD for (CeedInt k = 0; k < num_comp; k++) {
66             CeedPragmaSIMD for (CeedInt n = 0; n < elem_size; n++) {
67               CeedPragmaSIMD for (CeedInt j = 0; j < blk_size; j++) {
68                 vv[e * elem_size * num_comp + (k * elem_size + n) * blk_size + j - v_offset] =
69                     uu[n * strides[0] + k * strides[1] + CeedIntMin(e + j, num_elem - 1) * strides[2]];
70               }
71             }
72           }
73         }
74       }
75     } else {
76       // Offsets provided, standard or blocked restriction
77       // vv has shape [elem_size, num_comp, num_elem], row-major
78       // uu has shape [nnodes, num_comp]
79       for (CeedInt e = start * blk_size; e < stop * blk_size; e += blk_size) {
80         CeedPragmaSIMD for (CeedInt k = 0; k < num_comp; k++) {
81           CeedPragmaSIMD for (CeedInt i = 0; i < elem_size * blk_size; i++) {
82             if (!use_orient || !impl->orient) {
83               // Unsigned restriction
84               vv[elem_size * (k * blk_size + num_comp * e) + i - v_offset] = uu[impl->offsets[i + elem_size * e] + k * comp_stride];
85             } else {
86               // Signed restriction
87               vv[elem_size * (k * blk_size + num_comp * e) + i - v_offset] =
88                   uu[impl->offsets[i + elem_size * e] + k * comp_stride] * (impl->orient[i + elem_size * e] ? -1.0 : 1.0);
89             }
90           }
91         }
92       }
93     }
94   } else {
95     // Restriction from E-vector to L-vector
96     // Performing v += r^T * u
97     // No offsets provided, Identity Restriction
98     if (!impl->offsets) {
99       bool has_backend_strides;
100       CeedCallBackend(CeedElemRestrictionHasBackendStrides(r, &has_backend_strides));
101       if (has_backend_strides) {
102         // CPU backend strides are {1, elem_size, elem_size*num_comp}
103         // This if brach is left separate to allow better inlining
104         for (CeedInt e = start * blk_size; e < stop * blk_size; e += blk_size) {
105           CeedPragmaSIMD for (CeedInt k = 0; k < num_comp; k++) {
106             CeedPragmaSIMD for (CeedInt n = 0; n < elem_size; n++) {
107               CeedPragmaSIMD for (CeedInt j = 0; j < CeedIntMin(blk_size, num_elem - e); j++) {
108                 vv[n + k * elem_size + (e + j) * elem_size * num_comp] +=
109                     uu[e * elem_size * num_comp + (k * elem_size + n) * blk_size + j - v_offset];
110               }
111             }
112           }
113         }
114       } else {
115         // User provided strides
116         CeedInt strides[3];
117         CeedCallBackend(CeedElemRestrictionGetStrides(r, &strides));
118         for (CeedInt e = start * blk_size; e < stop * blk_size; e += blk_size) {
119           CeedPragmaSIMD for (CeedInt k = 0; k < num_comp; k++) {
120             CeedPragmaSIMD for (CeedInt n = 0; n < elem_size; n++) {
121               CeedPragmaSIMD for (CeedInt j = 0; j < CeedIntMin(blk_size, num_elem - e); j++) {
122                 vv[n * strides[0] + k * strides[1] + (e + j) * strides[2]] +=
123                     uu[e * elem_size * num_comp + (k * elem_size + n) * blk_size + j - v_offset];
124               }
125             }
126           }
127         }
128       }
129     } else {
130       // Offsets provided, standard or blocked restriction
131       // uu has shape [elem_size, num_comp, num_elem]
132       // vv has shape [nnodes, num_comp]
133       for (CeedInt e = start * blk_size; e < stop * blk_size; e += blk_size) {
134         for (CeedInt k = 0; k < num_comp; k++) {
135           for (CeedInt i = 0; i < elem_size * blk_size; i += blk_size) {
136             // Iteration bound set to discard padding elements
137             for (CeedInt j = i; j < i + CeedIntMin(blk_size, num_elem - e); j++) {
138               if (!use_orient || !impl->orient) {
139                 // Unsigned restriction
140                 vv[impl->offsets[j + e * elem_size] + k * comp_stride] += uu[elem_size * (k * blk_size + num_comp * e) + j - v_offset];
141               } else {
142                 // Signed restriction
143                 vv[impl->offsets[j + e * elem_size] + k * comp_stride] +=
144                     uu[elem_size * (k * blk_size + num_comp * e) + j - v_offset] * (impl->orient[j + e * elem_size] ? -1.0 : 1.0);
145               }
146             }
147           }
148         }
149       }
150     }
151   }
152   CeedCallBackend(CeedVectorRestoreArrayRead(u, &uu));
153   CeedCallBackend(CeedVectorRestoreArray(v, &vv));
154   if (request != CEED_REQUEST_IMMEDIATE && request != CEED_REQUEST_ORDERED) *request = NULL;
155   return CEED_ERROR_SUCCESS;
156 }
157 
158 //------------------------------------------------------------------------------
159 // ElemRestriction Apply - Common Sizes
160 //------------------------------------------------------------------------------
161 static int CeedElemRestrictionApply_Ref_110(CeedElemRestriction r, const CeedInt num_comp, const CeedInt blk_size, const CeedInt comp_stride,
162                                             CeedInt start, CeedInt stop, bool use_orient, CeedTransposeMode t_mode, CeedVector u, CeedVector v,
163                                             CeedRequest *request) {
164   return CeedElemRestrictionApply_Ref_Core(r, 1, 1, comp_stride, start, stop, use_orient, t_mode, u, v, request);
165 }
166 
167 static int CeedElemRestrictionApply_Ref_111(CeedElemRestriction r, const CeedInt num_comp, const CeedInt blk_size, const CeedInt comp_stride,
168                                             CeedInt start, CeedInt stop, bool use_orient, CeedTransposeMode t_mode, CeedVector u, CeedVector v,
169                                             CeedRequest *request) {
170   return CeedElemRestrictionApply_Ref_Core(r, 1, 1, 1, start, stop, use_orient, t_mode, u, v, request);
171 }
172 
173 static int CeedElemRestrictionApply_Ref_180(CeedElemRestriction r, const CeedInt num_comp, const CeedInt blk_size, const CeedInt comp_stride,
174                                             CeedInt start, CeedInt stop, bool use_orient, CeedTransposeMode t_mode, CeedVector u, CeedVector v,
175                                             CeedRequest *request) {
176   return CeedElemRestrictionApply_Ref_Core(r, 1, 8, comp_stride, start, stop, use_orient, t_mode, u, v, request);
177 }
178 
179 static int CeedElemRestrictionApply_Ref_181(CeedElemRestriction r, const CeedInt num_comp, const CeedInt blk_size, const CeedInt comp_stride,
180                                             CeedInt start, CeedInt stop, bool use_orient, CeedTransposeMode t_mode, CeedVector u, CeedVector v,
181                                             CeedRequest *request) {
182   return CeedElemRestrictionApply_Ref_Core(r, 1, 8, 1, start, stop, use_orient, t_mode, u, v, request);
183 }
184 
185 static int CeedElemRestrictionApply_Ref_310(CeedElemRestriction r, const CeedInt num_comp, const CeedInt blk_size, const CeedInt comp_stride,
186                                             CeedInt start, CeedInt stop, bool use_orient, CeedTransposeMode t_mode, CeedVector u, CeedVector v,
187                                             CeedRequest *request) {
188   return CeedElemRestrictionApply_Ref_Core(r, 3, 1, comp_stride, start, stop, use_orient, t_mode, u, v, request);
189 }
190 
191 static int CeedElemRestrictionApply_Ref_311(CeedElemRestriction r, const CeedInt num_comp, const CeedInt blk_size, const CeedInt comp_stride,
192                                             CeedInt start, CeedInt stop, bool use_orient, CeedTransposeMode t_mode, CeedVector u, CeedVector v,
193                                             CeedRequest *request) {
194   return CeedElemRestrictionApply_Ref_Core(r, 3, 1, 1, start, stop, use_orient, t_mode, u, v, request);
195 }
196 
197 static int CeedElemRestrictionApply_Ref_380(CeedElemRestriction r, const CeedInt num_comp, const CeedInt blk_size, const CeedInt comp_stride,
198                                             CeedInt start, CeedInt stop, bool use_orient, CeedTransposeMode t_mode, CeedVector u, CeedVector v,
199                                             CeedRequest *request) {
200   return CeedElemRestrictionApply_Ref_Core(r, 3, 8, comp_stride, start, stop, use_orient, t_mode, u, v, request);
201 }
202 
203 static int CeedElemRestrictionApply_Ref_381(CeedElemRestriction r, const CeedInt num_comp, const CeedInt blk_size, const CeedInt comp_stride,
204                                             CeedInt start, CeedInt stop, bool use_orient, CeedTransposeMode t_mode, CeedVector u, CeedVector v,
205                                             CeedRequest *request) {
206   return CeedElemRestrictionApply_Ref_Core(r, 3, 8, 1, start, stop, use_orient, t_mode, u, v, request);
207 }
208 
209 // LCOV_EXCL_START
210 static int CeedElemRestrictionApply_Ref_510(CeedElemRestriction r, const CeedInt num_comp, const CeedInt blk_size, const CeedInt comp_stride,
211                                             CeedInt start, CeedInt stop, bool use_orient, CeedTransposeMode t_mode, CeedVector u, CeedVector v,
212                                             CeedRequest *request) {
213   return CeedElemRestrictionApply_Ref_Core(r, 5, 1, comp_stride, start, stop, use_orient, t_mode, u, v, request);
214 }
215 // LCOV_EXCL_STOP
216 
217 static int CeedElemRestrictionApply_Ref_511(CeedElemRestriction r, const CeedInt num_comp, const CeedInt blk_size, const CeedInt comp_stride,
218                                             CeedInt start, CeedInt stop, bool use_orient, CeedTransposeMode t_mode, CeedVector u, CeedVector v,
219                                             CeedRequest *request) {
220   return CeedElemRestrictionApply_Ref_Core(r, 5, 1, 1, start, stop, use_orient, t_mode, u, v, request);
221 }
222 
223 // LCOV_EXCL_START
224 static int CeedElemRestrictionApply_Ref_580(CeedElemRestriction r, const CeedInt num_comp, const CeedInt blk_size, const CeedInt comp_stride,
225                                             CeedInt start, CeedInt stop, bool use_orient, CeedTransposeMode t_mode, CeedVector u, CeedVector v,
226                                             CeedRequest *request) {
227   return CeedElemRestrictionApply_Ref_Core(r, 5, 8, comp_stride, start, stop, use_orient, t_mode, u, v, request);
228 }
229 // LCOV_EXCL_STOP
230 
231 static int CeedElemRestrictionApply_Ref_581(CeedElemRestriction r, const CeedInt num_comp, const CeedInt blk_size, const CeedInt comp_stride,
232                                             CeedInt start, CeedInt stop, bool use_orient, CeedTransposeMode t_mode, CeedVector u, CeedVector v,
233                                             CeedRequest *request) {
234   return CeedElemRestrictionApply_Ref_Core(r, 5, 8, 1, start, stop, use_orient, t_mode, u, v, request);
235 }
236 
237 //------------------------------------------------------------------------------
238 // ElemRestriction Apply
239 //------------------------------------------------------------------------------
240 static int CeedElemRestrictionApply_Ref(CeedElemRestriction r, CeedTransposeMode t_mode, CeedVector u, CeedVector v, CeedRequest *request) {
241   CeedInt num_blk, blk_size, num_comp, comp_stride;
242   CeedCallBackend(CeedElemRestrictionGetNumBlocks(r, &num_blk));
243   CeedCallBackend(CeedElemRestrictionGetBlockSize(r, &blk_size));
244   CeedCallBackend(CeedElemRestrictionGetNumComponents(r, &num_comp));
245   CeedCallBackend(CeedElemRestrictionGetCompStride(r, &comp_stride));
246   CeedElemRestriction_Ref *impl;
247   CeedCallBackend(CeedElemRestrictionGetData(r, &impl));
248 
249   return impl->Apply(r, num_comp, blk_size, comp_stride, 0, num_blk, true, t_mode, u, v, request);
250 }
251 
252 //------------------------------------------------------------------------------
253 // ElemRestriction Apply Unsigned
254 //------------------------------------------------------------------------------
255 static int CeedElemRestrictionApplyUnsigned_Ref(CeedElemRestriction r, CeedTransposeMode t_mode, CeedVector u, CeedVector v, CeedRequest *request) {
256   CeedInt num_blk, blk_size, num_comp, comp_stride;
257   CeedCallBackend(CeedElemRestrictionGetNumBlocks(r, &num_blk));
258   CeedCallBackend(CeedElemRestrictionGetBlockSize(r, &blk_size));
259   CeedCallBackend(CeedElemRestrictionGetNumComponents(r, &num_comp));
260   CeedCallBackend(CeedElemRestrictionGetCompStride(r, &comp_stride));
261   CeedElemRestriction_Ref *impl;
262   CeedCallBackend(CeedElemRestrictionGetData(r, &impl));
263 
264   return impl->Apply(r, num_comp, blk_size, comp_stride, 0, num_blk, false, t_mode, u, v, request);
265 }
266 
267 //------------------------------------------------------------------------------
268 // ElemRestriction Apply Block
269 //------------------------------------------------------------------------------
270 static int CeedElemRestrictionApplyBlock_Ref(CeedElemRestriction r, CeedInt block, CeedTransposeMode t_mode, CeedVector u, CeedVector v,
271                                              CeedRequest *request) {
272   CeedInt blk_size, num_comp, comp_stride;
273   CeedCallBackend(CeedElemRestrictionGetBlockSize(r, &blk_size));
274   CeedCallBackend(CeedElemRestrictionGetNumComponents(r, &num_comp));
275   CeedCallBackend(CeedElemRestrictionGetCompStride(r, &comp_stride));
276   CeedElemRestriction_Ref *impl;
277   CeedCallBackend(CeedElemRestrictionGetData(r, &impl));
278 
279   return impl->Apply(r, num_comp, blk_size, comp_stride, block, block + 1, true, t_mode, u, v, request);
280 }
281 
282 //------------------------------------------------------------------------------
283 // ElemRestriction Get Offsets
284 //------------------------------------------------------------------------------
285 static int CeedElemRestrictionGetOffsets_Ref(CeedElemRestriction rstr, CeedMemType mem_type, const CeedInt **offsets) {
286   CeedElemRestriction_Ref *impl;
287   CeedCallBackend(CeedElemRestrictionGetData(rstr, &impl));
288   Ceed ceed;
289   CeedCallBackend(CeedElemRestrictionGetCeed(rstr, &ceed));
290 
291   CeedCheck(mem_type == CEED_MEM_HOST, ceed, CEED_ERROR_BACKEND, "Can only provide to HOST memory");
292 
293   *offsets = impl->offsets;
294   return CEED_ERROR_SUCCESS;
295 }
296 
297 //------------------------------------------------------------------------------
298 // ElemRestriction Destroy
299 //------------------------------------------------------------------------------
300 static int CeedElemRestrictionDestroy_Ref(CeedElemRestriction r) {
301   CeedElemRestriction_Ref *impl;
302   CeedCallBackend(CeedElemRestrictionGetData(r, &impl));
303 
304   CeedCallBackend(CeedFree(&impl->offsets_allocated));
305   CeedCallBackend(CeedFree(&impl->orient_allocated));
306   CeedCallBackend(CeedFree(&impl));
307   return CEED_ERROR_SUCCESS;
308 }
309 
310 //------------------------------------------------------------------------------
311 // ElemRestriction Create
312 //------------------------------------------------------------------------------
313 int CeedElemRestrictionCreate_Ref(CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, CeedElemRestriction r) {
314   CeedElemRestriction_Ref *impl;
315   CeedInt                  num_elem, elem_size, num_blk, blk_size, num_comp, comp_stride;
316   CeedCallBackend(CeedElemRestrictionGetNumElements(r, &num_elem));
317   CeedCallBackend(CeedElemRestrictionGetElementSize(r, &elem_size));
318   CeedCallBackend(CeedElemRestrictionGetNumBlocks(r, &num_blk));
319   CeedCallBackend(CeedElemRestrictionGetBlockSize(r, &blk_size));
320   CeedCallBackend(CeedElemRestrictionGetNumComponents(r, &num_comp));
321   CeedCallBackend(CeedElemRestrictionGetCompStride(r, &comp_stride));
322   Ceed ceed;
323   CeedCallBackend(CeedElemRestrictionGetCeed(r, &ceed));
324 
325   CeedCheck(mem_type == CEED_MEM_HOST, ceed, CEED_ERROR_BACKEND, "Only MemType = HOST supported");
326   CeedCallBackend(CeedCalloc(1, &impl));
327 
328   // Offsets data
329   bool is_strided;
330   CeedCallBackend(CeedElemRestrictionIsStrided(r, &is_strided));
331   if (!is_strided) {
332     // Check indices for ref or memcheck backends
333     Ceed parent_ceed = ceed, curr_ceed = NULL;
334     while (parent_ceed != curr_ceed) {
335       curr_ceed = parent_ceed;
336       CeedCallBackend(CeedGetParent(curr_ceed, &parent_ceed));
337     }
338     const char *resource;
339     CeedCallBackend(CeedGetResource(parent_ceed, &resource));
340     if (!strcmp(resource, "/cpu/self/ref/serial") || !strcmp(resource, "/cpu/self/ref/blocked") || !strcmp(resource, "/cpu/self/memcheck/serial") ||
341         !strcmp(resource, "/cpu/self/memcheck/blocked")) {
342       CeedSize l_size;
343       CeedCallBackend(CeedElemRestrictionGetLVectorSize(r, &l_size));
344 
345       for (CeedInt i = 0; i < num_elem * elem_size; i++) {
346         CeedCheck(offsets[i] >= 0 && offsets[i] + (num_comp - 1) * comp_stride < l_size, ceed, CEED_ERROR_BACKEND,
347                   "Restriction offset %" CeedInt_FMT " (%" CeedInt_FMT ") out of range [0, %" CeedInt_FMT "]", i, offsets[i], l_size);
348       }
349     }
350 
351     // Copy data
352     switch (copy_mode) {
353       case CEED_COPY_VALUES:
354         CeedCallBackend(CeedMalloc(num_elem * elem_size, &impl->offsets_allocated));
355         memcpy(impl->offsets_allocated, offsets, num_elem * elem_size * sizeof(offsets[0]));
356         impl->offsets = impl->offsets_allocated;
357         break;
358       case CEED_OWN_POINTER:
359         impl->offsets_allocated = (CeedInt *)offsets;
360         impl->offsets           = impl->offsets_allocated;
361         break;
362       case CEED_USE_POINTER:
363         impl->offsets = offsets;
364     }
365   }
366 
367   CeedCallBackend(CeedElemRestrictionSetData(r, impl));
368   CeedInt layout[3] = {1, elem_size, elem_size * num_comp};
369   CeedCallBackend(CeedElemRestrictionSetELayout(r, layout));
370   CeedCallBackend(CeedSetBackendFunction(ceed, "ElemRestriction", r, "Apply", CeedElemRestrictionApply_Ref));
371   CeedCallBackend(CeedSetBackendFunction(ceed, "ElemRestriction", r, "ApplyUnsigned", CeedElemRestrictionApplyUnsigned_Ref));
372   CeedCallBackend(CeedSetBackendFunction(ceed, "ElemRestriction", r, "ApplyBlock", CeedElemRestrictionApplyBlock_Ref));
373   CeedCallBackend(CeedSetBackendFunction(ceed, "ElemRestriction", r, "GetOffsets", CeedElemRestrictionGetOffsets_Ref));
374   CeedCallBackend(CeedSetBackendFunction(ceed, "ElemRestriction", r, "Destroy", CeedElemRestrictionDestroy_Ref));
375 
376   // Set apply function based upon num_comp, blk_size, and comp_stride
377   CeedInt idx = -1;
378   if (blk_size < 10) idx = 100 * num_comp + 10 * blk_size + (comp_stride == 1);
379   switch (idx) {
380     case 110:
381       impl->Apply = CeedElemRestrictionApply_Ref_110;
382       break;
383     case 111:
384       impl->Apply = CeedElemRestrictionApply_Ref_111;
385       break;
386     case 180:
387       impl->Apply = CeedElemRestrictionApply_Ref_180;
388       break;
389     case 181:
390       impl->Apply = CeedElemRestrictionApply_Ref_181;
391       break;
392     case 310:
393       impl->Apply = CeedElemRestrictionApply_Ref_310;
394       break;
395     case 311:
396       impl->Apply = CeedElemRestrictionApply_Ref_311;
397       break;
398     case 380:
399       impl->Apply = CeedElemRestrictionApply_Ref_380;
400       break;
401     case 381:
402       impl->Apply = CeedElemRestrictionApply_Ref_381;
403       break;
404     // LCOV_EXCL_START
405     case 510:
406       impl->Apply = CeedElemRestrictionApply_Ref_510;
407       break;
408     // LCOV_EXCL_STOP
409     case 511:
410       impl->Apply = CeedElemRestrictionApply_Ref_511;
411       break;
412     // LCOV_EXCL_START
413     case 580:
414       impl->Apply = CeedElemRestrictionApply_Ref_580;
415       break;
416     // LCOV_EXCL_STOP
417     case 581:
418       impl->Apply = CeedElemRestrictionApply_Ref_581;
419       break;
420     default:
421       impl->Apply = CeedElemRestrictionApply_Ref_Core;
422       break;
423   }
424 
425   return CEED_ERROR_SUCCESS;
426 }
427 
428 //------------------------------------------------------------------------------
429 // ElemRestriction Create Oriented
430 //------------------------------------------------------------------------------
431 int CeedElemRestrictionCreateOriented_Ref(CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, const bool *orient,
432                                           CeedElemRestriction r) {
433   // Set up for normal restriction with explicit offsets. This sets up dispatch to
434   // CeedElemRestrictionApply_Ref_* and manages the impl->offsets array copy/allocation.
435   CeedElemRestriction_Ref *impl;
436   CeedInt                  num_elem, elem_size;
437   CeedCallBackend(CeedElemRestrictionCreate_Ref(mem_type, copy_mode, offsets, r));
438   CeedCallBackend(CeedElemRestrictionGetData(r, &impl));
439   CeedCallBackend(CeedElemRestrictionGetNumElements(r, &num_elem));
440   CeedCallBackend(CeedElemRestrictionGetElementSize(r, &elem_size));
441 
442   // Copy data
443   switch (copy_mode) {
444     case CEED_COPY_VALUES:
445       CeedCallBackend(CeedMalloc(num_elem * elem_size, &impl->orient_allocated));
446       memcpy(impl->orient_allocated, orient, num_elem * elem_size * sizeof(orient[0]));
447       impl->orient = impl->orient_allocated;
448       break;
449     case CEED_OWN_POINTER:
450       impl->orient_allocated = (bool *)orient;
451       impl->orient           = impl->orient_allocated;
452       break;
453     case CEED_USE_POINTER:
454       impl->orient = orient;
455   }
456 
457   return CEED_ERROR_SUCCESS;
458 }
459 
460 //------------------------------------------------------------------------------
461