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