xref: /libCEED/rust/libceed-sys/c-src/backends/ref/ceed-ref-basis.c (revision 3d8e882215d238700cdceb37404f76ca7fa24eaa)
1*3d8e8822SJeremy L Thompson // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors.
2*3d8e8822SJeremy L Thompson // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
321617c04Sjeremylt //
4*3d8e8822SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause
521617c04Sjeremylt //
6*3d8e8822SJeremy L Thompson // This file is part of CEED:  http://github.com/ceed
721617c04Sjeremylt 
8ec3da8bcSJed Brown #include <ceed/ceed.h>
9ec3da8bcSJed Brown #include <ceed/backend.h>
103d576824SJeremy L Thompson #include <math.h>
113d576824SJeremy L Thompson #include <stdbool.h>
123d576824SJeremy L Thompson #include <string.h>
1321617c04Sjeremylt #include "ceed-ref.h"
1421617c04Sjeremylt 
15f10650afSjeremylt //------------------------------------------------------------------------------
16f10650afSjeremylt // Basis Apply
17f10650afSjeremylt //------------------------------------------------------------------------------
18d1d35e2fSjeremylt static int CeedBasisApply_Ref(CeedBasis basis, CeedInt num_elem,
19d1d35e2fSjeremylt                               CeedTransposeMode t_mode, CeedEvalMode eval_mode,
20aedaa0e5Sjeremylt                               CeedVector U, CeedVector V) {
2121617c04Sjeremylt   int ierr;
224ce2993fSjeremylt   Ceed ceed;
23e15f9bd0SJeremy L Thompson   ierr = CeedBasisGetCeed(basis, &ceed); CeedChkBackend(ierr);
2450c301a5SRezgar Shakeri   CeedInt dim, num_comp, num_nodes, num_qpts, Q_comp;
25e15f9bd0SJeremy L Thompson   ierr = CeedBasisGetDimension(basis, &dim); CeedChkBackend(ierr);
26d1d35e2fSjeremylt   ierr = CeedBasisGetNumComponents(basis, &num_comp); CeedChkBackend(ierr);
27d1d35e2fSjeremylt   ierr = CeedBasisGetNumNodes(basis, &num_nodes); CeedChkBackend(ierr);
28d1d35e2fSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis, &num_qpts); CeedChkBackend(ierr);
2950c301a5SRezgar Shakeri   ierr = CeedBasisGetNumQuadratureComponents(basis, &Q_comp);
3050c301a5SRezgar Shakeri   CeedChkBackend(ierr);
312f86a920SJeremy L Thompson   CeedTensorContract contract;
32e15f9bd0SJeremy L Thompson   ierr = CeedBasisGetTensorContract(basis, &contract); CeedChkBackend(ierr);
33d1d35e2fSjeremylt   const CeedInt add = (t_mode == CEED_TRANSPOSE);
34aedaa0e5Sjeremylt   const CeedScalar *u;
35aedaa0e5Sjeremylt   CeedScalar *v;
36a7b7f929Sjeremylt   if (U != CEED_VECTOR_NONE) {
37e15f9bd0SJeremy L Thompson     ierr = CeedVectorGetArrayRead(U, CEED_MEM_HOST, &u); CeedChkBackend(ierr);
38d1d35e2fSjeremylt   } else if (eval_mode != CEED_EVAL_WEIGHT) {
39c042f62fSJeremy L Thompson     // LCOV_EXCL_START
40e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_BACKEND,
41aedaa0e5Sjeremylt                      "An input vector is required for this CeedEvalMode");
42c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
43aedaa0e5Sjeremylt   }
449c774eddSJeremy L Thompson   ierr = CeedVectorGetArrayWrite(V, CEED_MEM_HOST, &v); CeedChkBackend(ierr);
4521617c04Sjeremylt 
468d94b059Sjeremylt   // Clear v if operating in transpose
47d1d35e2fSjeremylt   if (t_mode == CEED_TRANSPOSE) {
48d1d35e2fSjeremylt     const CeedInt v_size = num_elem*num_comp*num_nodes;
49d1d35e2fSjeremylt     for (CeedInt i = 0; i < v_size; i++)
5084a01de5SJeremy L Thompson       v[i] = (CeedScalar) 0.0;
5121617c04Sjeremylt   }
52d1d35e2fSjeremylt   bool tensor_basis;
53d1d35e2fSjeremylt   ierr = CeedBasisIsTensor(basis, &tensor_basis); CeedChkBackend(ierr);
5484a01de5SJeremy L Thompson   // Tensor basis
55d1d35e2fSjeremylt   if (tensor_basis) {
56d1d35e2fSjeremylt     CeedInt P_1d, Q_1d;
57d1d35e2fSjeremylt     ierr = CeedBasisGetNumNodes1D(basis, &P_1d); CeedChkBackend(ierr);
58d1d35e2fSjeremylt     ierr = CeedBasisGetNumQuadraturePoints1D(basis, &Q_1d); CeedChkBackend(ierr);
59d1d35e2fSjeremylt     switch (eval_mode) {
608d94b059Sjeremylt     // Interpolate to/from quadrature points
61a2b73c81Sjeremylt     case CEED_EVAL_INTERP: {
62dfe03796SJeremy L Thompson       CeedBasis_Ref *impl;
63e15f9bd0SJeremy L Thompson       ierr = CeedBasisGetData(basis, &impl); CeedChkBackend(ierr);
648c1105f8SJeremy L Thompson       if (impl->has_collo_interp) {
65d1d35e2fSjeremylt         memcpy(v, u, num_elem*num_comp*num_nodes*sizeof(u[0]));
66dfe03796SJeremy L Thompson       } else {
67d1d35e2fSjeremylt         CeedInt P = P_1d, Q = Q_1d;
68d1d35e2fSjeremylt         if (t_mode == CEED_TRANSPOSE) {
69d1d35e2fSjeremylt           P = Q_1d; Q = P_1d;
7021617c04Sjeremylt         }
71d1d35e2fSjeremylt         CeedInt pre = num_comp*CeedIntPow(P, dim-1), post = num_elem;
72d1d35e2fSjeremylt         CeedScalar tmp[2][num_elem*num_comp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
73d1d35e2fSjeremylt         const CeedScalar *interp_1d;
74d1d35e2fSjeremylt         ierr = CeedBasisGetInterp1D(basis, &interp_1d); CeedChkBackend(ierr);
7521617c04Sjeremylt         for (CeedInt d=0; d<dim; d++) {
762f86a920SJeremy L Thompson           ierr = CeedTensorContractApply(contract, pre, P, post, Q,
77d1d35e2fSjeremylt                                          interp_1d, t_mode, add&&(d==dim-1),
78dfe03796SJeremy L Thompson                                          d==0?u:tmp[d%2],
79dfe03796SJeremy L Thompson                                          d==dim-1?v:tmp[(d+1)%2]);
80e15f9bd0SJeremy L Thompson           CeedChkBackend(ierr);
8121617c04Sjeremylt           pre /= P;
8221617c04Sjeremylt           post *= Q;
8321617c04Sjeremylt         }
84dfe03796SJeremy L Thompson       }
85a2b73c81Sjeremylt     } break;
868d94b059Sjeremylt     // Evaluate the gradient to/from quadrature points
87a2b73c81Sjeremylt     case CEED_EVAL_GRAD: {
8821617c04Sjeremylt       // In CEED_NOTRANSPOSE mode:
89d1d35e2fSjeremylt       // u has shape [dim, num_comp, P^dim, num_elem], row-major layout
90d1d35e2fSjeremylt       // v has shape [dim, num_comp, Q^dim, num_elem], row-major layout
9121617c04Sjeremylt       // In CEED_TRANSPOSE mode, the sizes of u and v are switched.
92d1d35e2fSjeremylt       CeedInt P = P_1d, Q = Q_1d;
93d1d35e2fSjeremylt       if (t_mode == CEED_TRANSPOSE) {
94d1d35e2fSjeremylt         P = Q_1d, Q = Q_1d;
9521617c04Sjeremylt       }
9684a01de5SJeremy L Thompson       CeedBasis_Ref *impl;
97e15f9bd0SJeremy L Thompson       ierr = CeedBasisGetData(basis, &impl); CeedChkBackend(ierr);
98d1d35e2fSjeremylt       CeedInt pre = num_comp*CeedIntPow(P, dim-1), post = num_elem;
99d1d35e2fSjeremylt       const CeedScalar *interp_1d;
100d1d35e2fSjeremylt       ierr = CeedBasisGetInterp1D(basis, &interp_1d); CeedChkBackend(ierr);
1018c1105f8SJeremy L Thompson       if (impl->collo_grad_1d) {
102d1d35e2fSjeremylt         CeedScalar tmp[2][num_elem*num_comp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
103d1d35e2fSjeremylt         CeedScalar interp[num_elem*num_comp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
10484a01de5SJeremy L Thompson         // Interpolate to quadrature points (NoTranspose)
10584a01de5SJeremy L Thompson         //  or Grad to quadrature points (Transpose)
10621617c04Sjeremylt         for (CeedInt d=0; d<dim; d++) {
1072f86a920SJeremy L Thompson           ierr = CeedTensorContractApply(contract, pre, P, post, Q,
108d1d35e2fSjeremylt                                          (t_mode == CEED_NOTRANSPOSE
109d1d35e2fSjeremylt                                           ? interp_1d
1108c1105f8SJeremy L Thompson                                           : impl->collo_grad_1d),
111d1d35e2fSjeremylt                                          t_mode, add&&(d>0),
112d1d35e2fSjeremylt                                          (t_mode == CEED_NOTRANSPOSE
11384a01de5SJeremy L Thompson                                           ? (d==0?u:tmp[d%2])
114d1d35e2fSjeremylt                                           : u + d*num_qpts*num_comp*num_elem),
115d1d35e2fSjeremylt                                          (t_mode == CEED_NOTRANSPOSE
11684a01de5SJeremy L Thompson                                           ? (d==dim-1?interp:tmp[(d+1)%2])
11784a01de5SJeremy L Thompson                                           : interp));
118e15f9bd0SJeremy L Thompson           CeedChkBackend(ierr);
11921617c04Sjeremylt           pre /= P;
12021617c04Sjeremylt           post *= Q;
12121617c04Sjeremylt         }
12284a01de5SJeremy L Thompson         // Grad to quadrature points (NoTranspose)
1238795c945Sjeremylt         //  or Interpolate to nodes (Transpose)
124d1d35e2fSjeremylt         P = Q_1d, Q = Q_1d;
125d1d35e2fSjeremylt         if (t_mode == CEED_TRANSPOSE) {
126d1d35e2fSjeremylt           P = Q_1d, Q = P_1d;
12784a01de5SJeremy L Thompson         }
128d1d35e2fSjeremylt         pre = num_comp*CeedIntPow(P, dim-1), post = num_elem;
12984a01de5SJeremy L Thompson         for (CeedInt d=0; d<dim; d++) {
1302f86a920SJeremy L Thompson           ierr = CeedTensorContractApply(contract, pre, P, post, Q,
131d1d35e2fSjeremylt                                          (t_mode == CEED_NOTRANSPOSE
1328c1105f8SJeremy L Thompson                                           ? impl->collo_grad_1d
133d1d35e2fSjeremylt                                           : interp_1d),
134d1d35e2fSjeremylt                                          t_mode, add&&(d==dim-1),
135d1d35e2fSjeremylt                                          (t_mode == CEED_NOTRANSPOSE
13684a01de5SJeremy L Thompson                                           ? interp
13784a01de5SJeremy L Thompson                                           : (d==0?interp:tmp[d%2])),
138d1d35e2fSjeremylt                                          (t_mode == CEED_NOTRANSPOSE
139d1d35e2fSjeremylt                                           ? v + d*num_qpts*num_comp*num_elem
14084a01de5SJeremy L Thompson                                           : (d==dim-1?v:tmp[(d+1)%2])));
141e15f9bd0SJeremy L Thompson           CeedChkBackend(ierr);
14284a01de5SJeremy L Thompson           pre /= P;
14384a01de5SJeremy L Thompson           post *= Q;
14421617c04Sjeremylt         }
1458c1105f8SJeremy L Thompson       } else if (impl->has_collo_interp) { // Qpts collocated with nodes
146d1d35e2fSjeremylt         const CeedScalar *grad_1d;
147d1d35e2fSjeremylt         ierr = CeedBasisGetGrad1D(basis, &grad_1d); CeedChkBackend(ierr);
148dfe03796SJeremy L Thompson 
149dfe03796SJeremy L Thompson         // Dim contractions, identity in other directions
150d1d35e2fSjeremylt         CeedInt pre = num_comp*CeedIntPow(P, dim-1), post = num_elem;
151c6158135Sjeremylt         for (CeedInt d=0; d<dim; d++) {
152dfe03796SJeremy L Thompson           ierr = CeedTensorContractApply(contract, pre, P, post, Q,
153d1d35e2fSjeremylt                                          grad_1d, t_mode, add&&(d>0),
154d1d35e2fSjeremylt                                          t_mode == CEED_NOTRANSPOSE
155d1d35e2fSjeremylt                                          ? u : u+d*num_comp*num_qpts*num_elem,
156d1d35e2fSjeremylt                                          t_mode == CEED_TRANSPOSE
157d1d35e2fSjeremylt                                          ? v : v+d*num_comp*num_qpts*num_elem);
158e15f9bd0SJeremy L Thompson           CeedChkBackend(ierr);
159c6158135Sjeremylt           pre /= P;
160c6158135Sjeremylt           post *= Q;
161dfe03796SJeremy L Thompson         }
162a7bd39daSjeremylt       } else { // Underintegration, P > Q
163d1d35e2fSjeremylt         const CeedScalar *grad_1d;
164d1d35e2fSjeremylt         ierr = CeedBasisGetGrad1D(basis, &grad_1d); CeedChkBackend(ierr);
165a7bd39daSjeremylt 
166d1d35e2fSjeremylt         if (t_mode == CEED_TRANSPOSE) {
167d1d35e2fSjeremylt           P = Q_1d, Q = P_1d;
168a7bd39daSjeremylt         }
169d1d35e2fSjeremylt         CeedScalar tmp[2][num_elem*num_comp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
170a7bd39daSjeremylt 
171a7bd39daSjeremylt         // Dim**2 contractions, apply grad when pass == dim
172a7bd39daSjeremylt         for (CeedInt p=0; p<dim; p++) {
173d1d35e2fSjeremylt           CeedInt pre = num_comp*CeedIntPow(P, dim-1), post = num_elem;
174a7bd39daSjeremylt           for (CeedInt d=0; d<dim; d++) {
175a7bd39daSjeremylt             ierr = CeedTensorContractApply(contract, pre, P, post, Q,
176d1d35e2fSjeremylt                                            (p==d)? grad_1d : interp_1d,
177d1d35e2fSjeremylt                                            t_mode, add&&(d==dim-1),
178a7bd39daSjeremylt                                            (d == 0
179d1d35e2fSjeremylt                                             ? (t_mode == CEED_NOTRANSPOSE
180d1d35e2fSjeremylt                                                ? u : u+p*num_comp*num_qpts*num_elem)
181a7bd39daSjeremylt                                             : tmp[d%2]),
182a7bd39daSjeremylt                                            (d == dim-1
183d1d35e2fSjeremylt                                             ? (t_mode == CEED_TRANSPOSE
184d1d35e2fSjeremylt                                                ? v : v+p*num_comp*num_qpts*num_elem)
185a7bd39daSjeremylt                                             : tmp[(d+1)%2]));
186e15f9bd0SJeremy L Thompson             CeedChkBackend(ierr);
187a7bd39daSjeremylt             pre /= P;
188a7bd39daSjeremylt             post *= Q;
189a7bd39daSjeremylt           }
190a7bd39daSjeremylt         }
191a7bd39daSjeremylt       }
192a2b73c81Sjeremylt     } break;
1938d94b059Sjeremylt     // Retrieve interpolation weights
194a2b73c81Sjeremylt     case CEED_EVAL_WEIGHT: {
195d1d35e2fSjeremylt       if (t_mode == CEED_TRANSPOSE)
196c042f62fSJeremy L Thompson         // LCOV_EXCL_START
197e15f9bd0SJeremy L Thompson         return CeedError(ceed, CEED_ERROR_BACKEND,
19821617c04Sjeremylt                          "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE");
199c042f62fSJeremy L Thompson       // LCOV_EXCL_STOP
200d1d35e2fSjeremylt       CeedInt Q = Q_1d;
201d1d35e2fSjeremylt       const CeedScalar *q_weight_1d;
202d1d35e2fSjeremylt       ierr = CeedBasisGetQWeights(basis, &q_weight_1d); CeedChkBackend(ierr);
20321617c04Sjeremylt       for (CeedInt d=0; d<dim; d++) {
204b5cf12eeSjeremylt         CeedInt pre = CeedIntPow(Q, dim-d-1), post = CeedIntPow(Q, d);
205a2b73c81Sjeremylt         for (CeedInt i=0; i<pre; i++)
206a2b73c81Sjeremylt           for (CeedInt j=0; j<Q; j++)
20784a01de5SJeremy L Thompson             for (CeedInt k=0; k<post; k++) {
208d1d35e2fSjeremylt               CeedScalar w = q_weight_1d[j]
209d1d35e2fSjeremylt                              * (d == 0 ? 1 : v[((i*Q + j)*post + k)*num_elem]);
210d1d35e2fSjeremylt               for (CeedInt e=0; e<num_elem; e++)
211d1d35e2fSjeremylt                 v[((i*Q + j)*post + k)*num_elem + e] = w;
21284a01de5SJeremy L Thompson             }
21321617c04Sjeremylt       }
214a2b73c81Sjeremylt     } break;
215c042f62fSJeremy L Thompson     // LCOV_EXCL_START
2168d94b059Sjeremylt     // Evaluate the divergence to/from the quadrature points
217a2b73c81Sjeremylt     case CEED_EVAL_DIV:
218e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_DIV not supported");
2198d94b059Sjeremylt     // Evaluate the curl to/from the quadrature points
220a2b73c81Sjeremylt     case CEED_EVAL_CURL:
221e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_CURL not supported");
2228d94b059Sjeremylt     // Take no action, BasisApply should not have been called
223a2b73c81Sjeremylt     case CEED_EVAL_NONE:
224e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_BACKEND,
2254b8bea3bSJed Brown                        "CEED_EVAL_NONE does not make sense in this context");
226c042f62fSJeremy L Thompson       // LCOV_EXCL_STOP
22721617c04Sjeremylt     }
228a8de75f0Sjeremylt   } else {
229a8de75f0Sjeremylt     // Non-tensor basis
230d1d35e2fSjeremylt     switch (eval_mode) {
23184a01de5SJeremy L Thompson     // Interpolate to/from quadrature points
232a8de75f0Sjeremylt     case CEED_EVAL_INTERP: {
23350c301a5SRezgar Shakeri       CeedInt P = num_nodes, Q = Q_comp*num_qpts;
2346c58de82SJeremy L Thompson       const CeedScalar *interp;
235e15f9bd0SJeremy L Thompson       ierr = CeedBasisGetInterp(basis, &interp); CeedChkBackend(ierr);
236d1d35e2fSjeremylt       if (t_mode == CEED_TRANSPOSE) {
23750c301a5SRezgar Shakeri         P = Q_comp*num_qpts; Q = num_nodes;
238a8de75f0Sjeremylt       }
239d1d35e2fSjeremylt       ierr = CeedTensorContractApply(contract, num_comp, P, num_elem, Q,
240d1d35e2fSjeremylt                                      interp, t_mode, add, u, v);
241e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
242a8de75f0Sjeremylt     }
243a8de75f0Sjeremylt     break;
24484a01de5SJeremy L Thompson     // Evaluate the gradient to/from quadrature points
245a8de75f0Sjeremylt     case CEED_EVAL_GRAD: {
246d1d35e2fSjeremylt       CeedInt P = num_nodes, Q = num_qpts;
247d1d35e2fSjeremylt       CeedInt dim_stride = num_qpts * num_comp * num_elem;
248d1d35e2fSjeremylt       CeedInt grad_stride = num_qpts * num_nodes;
2496c58de82SJeremy L Thompson       const CeedScalar *grad;
250e15f9bd0SJeremy L Thompson       ierr = CeedBasisGetGrad(basis, &grad); CeedChkBackend(ierr);
251d1d35e2fSjeremylt       if (t_mode == CEED_TRANSPOSE) {
252d1d35e2fSjeremylt         P = num_qpts; Q = num_nodes;
253475a782bSnbeams         for (CeedInt d = 0; d < dim; d++) {
254d1d35e2fSjeremylt           ierr = CeedTensorContractApply(contract, num_comp, P, num_elem, Q,
255d1d35e2fSjeremylt                                          grad + d * grad_stride, t_mode, add,
256d1d35e2fSjeremylt                                          u + d * dim_stride, v); CeedChkBackend(ierr);
257475a782bSnbeams         }
258475a782bSnbeams       } else {
259475a782bSnbeams         for (CeedInt d = 0; d < dim; d++) {
260d1d35e2fSjeremylt           ierr = CeedTensorContractApply(contract, num_comp, P, num_elem, Q,
261d1d35e2fSjeremylt                                          grad + d * grad_stride, t_mode, add,
262d1d35e2fSjeremylt                                          u, v + d * dim_stride); CeedChkBackend(ierr);
263475a782bSnbeams         }
264475a782bSnbeams       }
265a8de75f0Sjeremylt     }
266a8de75f0Sjeremylt     break;
26784a01de5SJeremy L Thompson     // Retrieve interpolation weights
268a8de75f0Sjeremylt     case CEED_EVAL_WEIGHT: {
269d1d35e2fSjeremylt       if (t_mode == CEED_TRANSPOSE)
270c042f62fSJeremy L Thompson         // LCOV_EXCL_START
271e15f9bd0SJeremy L Thompson         return CeedError(ceed, CEED_ERROR_BACKEND,
272a8de75f0Sjeremylt                          "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE");
273c042f62fSJeremy L Thompson       // LCOV_EXCL_STOP
274d1d35e2fSjeremylt       const CeedScalar *q_weight;
275d1d35e2fSjeremylt       ierr = CeedBasisGetQWeights(basis, &q_weight); CeedChkBackend(ierr);
276d1d35e2fSjeremylt       for (CeedInt i=0; i<num_qpts; i++)
277d1d35e2fSjeremylt         for (CeedInt e=0; e<num_elem; e++)
278d1d35e2fSjeremylt           v[i*num_elem + e] = q_weight[i];
279a8de75f0Sjeremylt     } break;
28084a01de5SJeremy L Thompson     // Evaluate the divergence to/from the quadrature points
28150c301a5SRezgar Shakeri     case CEED_EVAL_DIV: {
28250c301a5SRezgar Shakeri       CeedInt P = num_nodes, Q = num_qpts;
28350c301a5SRezgar Shakeri       const CeedScalar *div;
28450c301a5SRezgar Shakeri       ierr = CeedBasisGetDiv(basis, &div); CeedChkBackend(ierr);
28550c301a5SRezgar Shakeri       if (t_mode == CEED_TRANSPOSE) {
28650c301a5SRezgar Shakeri         P = num_qpts; Q = num_nodes;
28750c301a5SRezgar Shakeri       }
28850c301a5SRezgar Shakeri       ierr = CeedTensorContractApply(contract, num_comp, P, num_elem, Q,
28950c301a5SRezgar Shakeri                                      div, t_mode, add, u, v);
29050c301a5SRezgar Shakeri       CeedChkBackend(ierr);
29150c301a5SRezgar Shakeri     } break;
29250c301a5SRezgar Shakeri     // LCOV_EXCL_START
29384a01de5SJeremy L Thompson     // Evaluate the curl to/from the quadrature points
294a8de75f0Sjeremylt     case CEED_EVAL_CURL:
295e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_CURL not supported");
29684a01de5SJeremy L Thompson     // Take no action, BasisApply should not have been called
297a8de75f0Sjeremylt     case CEED_EVAL_NONE:
298e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_BACKEND,
299a8de75f0Sjeremylt                        "CEED_EVAL_NONE does not make sense in this context");
300c042f62fSJeremy L Thompson       // LCOV_EXCL_STOP
301a8de75f0Sjeremylt     }
302a8de75f0Sjeremylt   }
303a7b7f929Sjeremylt   if (U != CEED_VECTOR_NONE) {
304e15f9bd0SJeremy L Thompson     ierr = CeedVectorRestoreArrayRead(U, &u); CeedChkBackend(ierr);
305aedaa0e5Sjeremylt   }
306e15f9bd0SJeremy L Thompson   ierr = CeedVectorRestoreArray(V, &v); CeedChkBackend(ierr);
307e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
30821617c04Sjeremylt }
30921617c04Sjeremylt 
310f10650afSjeremylt //------------------------------------------------------------------------------
31150c301a5SRezgar Shakeri // Basis Create Non-Tensor H^1
312f10650afSjeremylt //------------------------------------------------------------------------------
313f10650afSjeremylt int CeedBasisCreateH1_Ref(CeedElemTopology topo, CeedInt dim,
314d1d35e2fSjeremylt                           CeedInt num_nodes, CeedInt num_qpts,
315f10650afSjeremylt                           const CeedScalar *interp,
316f10650afSjeremylt                           const CeedScalar *grad,
317d1d35e2fSjeremylt                           const CeedScalar *q_ref,
318d1d35e2fSjeremylt                           const CeedScalar *q_weight,
319f10650afSjeremylt                           CeedBasis basis) {
320f10650afSjeremylt   int ierr;
321f10650afSjeremylt   Ceed ceed;
322e15f9bd0SJeremy L Thompson   ierr = CeedBasisGetCeed(basis, &ceed); CeedChkBackend(ierr);
323f10650afSjeremylt 
324f10650afSjeremylt   Ceed parent;
325e15f9bd0SJeremy L Thompson   ierr = CeedGetParent(ceed, &parent); CeedChkBackend(ierr);
326f10650afSjeremylt   CeedTensorContract contract;
327e15f9bd0SJeremy L Thompson   ierr = CeedTensorContractCreate(parent, basis, &contract); CeedChkBackend(ierr);
32834359f16Sjeremylt   ierr = CeedBasisSetTensorContract(basis, contract); CeedChkBackend(ierr);
329f10650afSjeremylt 
330f10650afSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Apply",
331e15f9bd0SJeremy L Thompson                                 CeedBasisApply_Ref); CeedChkBackend(ierr);
332f10650afSjeremylt 
333e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
334f10650afSjeremylt }
335f10650afSjeremylt 
336f10650afSjeremylt //------------------------------------------------------------------------------
33750c301a5SRezgar Shakeri // Basis Create Non-Tensor H(div)
33850c301a5SRezgar Shakeri //------------------------------------------------------------------------------
33950c301a5SRezgar Shakeri int CeedBasisCreateHdiv_Ref(CeedElemTopology topo, CeedInt dim,
34050c301a5SRezgar Shakeri                             CeedInt num_nodes, CeedInt num_qpts,
34150c301a5SRezgar Shakeri                             const CeedScalar *interp,
34250c301a5SRezgar Shakeri                             const CeedScalar *div,
34350c301a5SRezgar Shakeri                             const CeedScalar *q_ref,
34450c301a5SRezgar Shakeri                             const CeedScalar *q_weight,
34550c301a5SRezgar Shakeri                             CeedBasis basis) {
34650c301a5SRezgar Shakeri   int ierr;
34750c301a5SRezgar Shakeri   Ceed ceed;
34850c301a5SRezgar Shakeri   ierr = CeedBasisGetCeed(basis, &ceed); CeedChkBackend(ierr);
34950c301a5SRezgar Shakeri 
35050c301a5SRezgar Shakeri   Ceed parent;
35150c301a5SRezgar Shakeri   ierr = CeedGetParent(ceed, &parent); CeedChkBackend(ierr);
35250c301a5SRezgar Shakeri   CeedTensorContract contract;
35350c301a5SRezgar Shakeri   ierr = CeedTensorContractCreate(parent, basis, &contract); CeedChkBackend(ierr);
35450c301a5SRezgar Shakeri   ierr = CeedBasisSetTensorContract(basis, contract); CeedChkBackend(ierr);
35550c301a5SRezgar Shakeri 
35650c301a5SRezgar Shakeri   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Apply",
35750c301a5SRezgar Shakeri                                 CeedBasisApply_Ref); CeedChkBackend(ierr);
35850c301a5SRezgar Shakeri 
35950c301a5SRezgar Shakeri   return CEED_ERROR_SUCCESS;
36050c301a5SRezgar Shakeri }
36150c301a5SRezgar Shakeri 
36250c301a5SRezgar Shakeri //------------------------------------------------------------------------------
363f10650afSjeremylt // Basis Destroy Tensor
364f10650afSjeremylt //------------------------------------------------------------------------------
36584a01de5SJeremy L Thompson static int CeedBasisDestroyTensor_Ref(CeedBasis basis) {
36684a01de5SJeremy L Thompson   int ierr;
3672f86a920SJeremy L Thompson 
36884a01de5SJeremy L Thompson   CeedBasis_Ref *impl;
369e15f9bd0SJeremy L Thompson   ierr = CeedBasisGetData(basis, &impl); CeedChkBackend(ierr);
3708c1105f8SJeremy L Thompson   ierr = CeedFree(&impl->collo_grad_1d); CeedChkBackend(ierr);
371e15f9bd0SJeremy L Thompson   ierr = CeedFree(&impl); CeedChkBackend(ierr);
37284a01de5SJeremy L Thompson 
373e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
37421617c04Sjeremylt }
37521617c04Sjeremylt 
376f10650afSjeremylt //------------------------------------------------------------------------------
377f10650afSjeremylt // Basis Create Tensor
378f10650afSjeremylt //------------------------------------------------------------------------------
379d1d35e2fSjeremylt int CeedBasisCreateTensorH1_Ref(CeedInt dim, CeedInt P_1d,
380d1d35e2fSjeremylt                                 CeedInt Q_1d, const CeedScalar *interp_1d,
381d1d35e2fSjeremylt                                 const CeedScalar *grad_1d,
382d1d35e2fSjeremylt                                 const CeedScalar *q_ref_1d,
383d1d35e2fSjeremylt                                 const CeedScalar *q_weight_1d,
38421617c04Sjeremylt                                 CeedBasis basis) {
385fe2413ffSjeremylt   int ierr;
386fe2413ffSjeremylt   Ceed ceed;
387e15f9bd0SJeremy L Thompson   ierr = CeedBasisGetCeed(basis, &ceed); CeedChkBackend(ierr);
38884a01de5SJeremy L Thompson   CeedBasis_Ref *impl;
389e15f9bd0SJeremy L Thompson   ierr = CeedCalloc(1, &impl); CeedChkBackend(ierr);
390dfe03796SJeremy L Thompson   // Check for collocated interp
391d1d35e2fSjeremylt   if (Q_1d == P_1d) {
392dfe03796SJeremy L Thompson     bool collocated = 1;
393d1d35e2fSjeremylt     for (CeedInt i=0; i<P_1d; i++) {
394d1d35e2fSjeremylt       collocated = collocated && (fabs(interp_1d[i+P_1d*i] - 1.0) < 1e-14);
395d1d35e2fSjeremylt       for (CeedInt j=0; j<P_1d; j++)
396dfe03796SJeremy L Thompson         if (j != i)
397d1d35e2fSjeremylt           collocated = collocated && (fabs(interp_1d[j+P_1d*i]) < 1e-14);
398dfe03796SJeremy L Thompson     }
3998c1105f8SJeremy L Thompson     impl->has_collo_interp = collocated;
400dfe03796SJeremy L Thompson   }
401dfe03796SJeremy L Thompson   // Calculate collocated grad
4028c1105f8SJeremy L Thompson   if (Q_1d >= P_1d && !impl->has_collo_interp) {
4038c1105f8SJeremy L Thompson     ierr = CeedMalloc(Q_1d*Q_1d, &impl->collo_grad_1d); CeedChkBackend(ierr);
4048c1105f8SJeremy L Thompson     ierr = CeedBasisGetCollocatedGrad(basis, impl->collo_grad_1d);
405e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
406a7bd39daSjeremylt   }
407e15f9bd0SJeremy L Thompson   ierr = CeedBasisSetData(basis, impl); CeedChkBackend(ierr);
408fe2413ffSjeremylt 
4092f86a920SJeremy L Thompson   Ceed parent;
410e15f9bd0SJeremy L Thompson   ierr = CeedGetParent(ceed, &parent); CeedChkBackend(ierr);
4112f86a920SJeremy L Thompson   CeedTensorContract contract;
412e15f9bd0SJeremy L Thompson   ierr = CeedTensorContractCreate(parent, basis, &contract); CeedChkBackend(ierr);
41334359f16Sjeremylt   ierr = CeedBasisSetTensorContract(basis, contract); CeedChkBackend(ierr);
4142f86a920SJeremy L Thompson 
415fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Apply",
416e15f9bd0SJeremy L Thompson                                 CeedBasisApply_Ref); CeedChkBackend(ierr);
417fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Destroy",
418e15f9bd0SJeremy L Thompson                                 CeedBasisDestroyTensor_Ref); CeedChkBackend(ierr);
419e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
42021617c04Sjeremylt }
421a8de75f0Sjeremylt 
422f10650afSjeremylt //------------------------------------------------------------------------------
423