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