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