xref: /libCEED/rust/libceed-sys/c-src/backends/ref/ceed-ref-basis.c (revision 50c301a53d2cec48a2aa861bf6f38393f4831c2f)
121617c04Sjeremylt // Copyright (c) 2017-2018, Lawrence Livermore National Security, LLC.
221617c04Sjeremylt // Produced at the Lawrence Livermore National Laboratory. LLNL-CODE-734707.
321617c04Sjeremylt // All Rights reserved. See files LICENSE and NOTICE for details.
421617c04Sjeremylt //
521617c04Sjeremylt // This file is part of CEED, a collection of benchmarks, miniapps, software
621617c04Sjeremylt // libraries and APIs for efficient high-order finite element and spectral
721617c04Sjeremylt // element discretizations for exascale applications. For more information and
821617c04Sjeremylt // source code availability see http://github.com/ceed.
921617c04Sjeremylt //
1021617c04Sjeremylt // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
1121617c04Sjeremylt // a collaborative effort of two U.S. Department of Energy organizations (Office
1221617c04Sjeremylt // of Science and the National Nuclear Security Administration) responsible for
1321617c04Sjeremylt // the planning and preparation of a capable exascale ecosystem, including
1421617c04Sjeremylt // software, applications, hardware, advanced system engineering and early
1521617c04Sjeremylt // testbed platforms, in support of the nation's exascale computing imperative.
1621617c04Sjeremylt 
17ec3da8bcSJed Brown #include <ceed/ceed.h>
18ec3da8bcSJed Brown #include <ceed/backend.h>
193d576824SJeremy L Thompson #include <math.h>
203d576824SJeremy L Thompson #include <stdbool.h>
213d576824SJeremy L Thompson #include <string.h>
2221617c04Sjeremylt #include "ceed-ref.h"
2321617c04Sjeremylt 
24f10650afSjeremylt //------------------------------------------------------------------------------
25f10650afSjeremylt // Basis Apply
26f10650afSjeremylt //------------------------------------------------------------------------------
27d1d35e2fSjeremylt static int CeedBasisApply_Ref(CeedBasis basis, CeedInt num_elem,
28d1d35e2fSjeremylt                               CeedTransposeMode t_mode, CeedEvalMode eval_mode,
29aedaa0e5Sjeremylt                               CeedVector U, CeedVector V) {
3021617c04Sjeremylt   int ierr;
314ce2993fSjeremylt   Ceed ceed;
32e15f9bd0SJeremy L Thompson   ierr = CeedBasisGetCeed(basis, &ceed); CeedChkBackend(ierr);
33*50c301a5SRezgar Shakeri   CeedInt dim, num_comp, num_nodes, num_qpts, Q_comp;
34e15f9bd0SJeremy L Thompson   ierr = CeedBasisGetDimension(basis, &dim); CeedChkBackend(ierr);
35d1d35e2fSjeremylt   ierr = CeedBasisGetNumComponents(basis, &num_comp); CeedChkBackend(ierr);
36d1d35e2fSjeremylt   ierr = CeedBasisGetNumNodes(basis, &num_nodes); CeedChkBackend(ierr);
37d1d35e2fSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis, &num_qpts); CeedChkBackend(ierr);
38*50c301a5SRezgar Shakeri   ierr = CeedBasisGetNumQuadratureComponents(basis, &Q_comp);
39*50c301a5SRezgar Shakeri   CeedChkBackend(ierr);
402f86a920SJeremy L Thompson   CeedTensorContract contract;
41e15f9bd0SJeremy L Thompson   ierr = CeedBasisGetTensorContract(basis, &contract); CeedChkBackend(ierr);
42d1d35e2fSjeremylt   const CeedInt add = (t_mode == CEED_TRANSPOSE);
43aedaa0e5Sjeremylt   const CeedScalar *u;
44aedaa0e5Sjeremylt   CeedScalar *v;
45a7b7f929Sjeremylt   if (U != CEED_VECTOR_NONE) {
46e15f9bd0SJeremy L Thompson     ierr = CeedVectorGetArrayRead(U, CEED_MEM_HOST, &u); CeedChkBackend(ierr);
47d1d35e2fSjeremylt   } else if (eval_mode != CEED_EVAL_WEIGHT) {
48c042f62fSJeremy L Thompson     // LCOV_EXCL_START
49e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_BACKEND,
50aedaa0e5Sjeremylt                      "An input vector is required for this CeedEvalMode");
51c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
52aedaa0e5Sjeremylt   }
539c774eddSJeremy L Thompson   ierr = CeedVectorGetArrayWrite(V, CEED_MEM_HOST, &v); CeedChkBackend(ierr);
5421617c04Sjeremylt 
558d94b059Sjeremylt   // Clear v if operating in transpose
56d1d35e2fSjeremylt   if (t_mode == CEED_TRANSPOSE) {
57d1d35e2fSjeremylt     const CeedInt v_size = num_elem*num_comp*num_nodes;
58d1d35e2fSjeremylt     for (CeedInt i = 0; i < v_size; i++)
5984a01de5SJeremy L Thompson       v[i] = (CeedScalar) 0.0;
6021617c04Sjeremylt   }
61d1d35e2fSjeremylt   bool tensor_basis;
62d1d35e2fSjeremylt   ierr = CeedBasisIsTensor(basis, &tensor_basis); CeedChkBackend(ierr);
6384a01de5SJeremy L Thompson   // Tensor basis
64d1d35e2fSjeremylt   if (tensor_basis) {
65d1d35e2fSjeremylt     CeedInt P_1d, Q_1d;
66d1d35e2fSjeremylt     ierr = CeedBasisGetNumNodes1D(basis, &P_1d); CeedChkBackend(ierr);
67d1d35e2fSjeremylt     ierr = CeedBasisGetNumQuadraturePoints1D(basis, &Q_1d); CeedChkBackend(ierr);
68d1d35e2fSjeremylt     switch (eval_mode) {
698d94b059Sjeremylt     // Interpolate to/from quadrature points
70a2b73c81Sjeremylt     case CEED_EVAL_INTERP: {
71dfe03796SJeremy L Thompson       CeedBasis_Ref *impl;
72e15f9bd0SJeremy L Thompson       ierr = CeedBasisGetData(basis, &impl); CeedChkBackend(ierr);
738c1105f8SJeremy L Thompson       if (impl->has_collo_interp) {
74d1d35e2fSjeremylt         memcpy(v, u, num_elem*num_comp*num_nodes*sizeof(u[0]));
75dfe03796SJeremy L Thompson       } else {
76d1d35e2fSjeremylt         CeedInt P = P_1d, Q = Q_1d;
77d1d35e2fSjeremylt         if (t_mode == CEED_TRANSPOSE) {
78d1d35e2fSjeremylt           P = Q_1d; Q = P_1d;
7921617c04Sjeremylt         }
80d1d35e2fSjeremylt         CeedInt pre = num_comp*CeedIntPow(P, dim-1), post = num_elem;
81d1d35e2fSjeremylt         CeedScalar tmp[2][num_elem*num_comp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
82d1d35e2fSjeremylt         const CeedScalar *interp_1d;
83d1d35e2fSjeremylt         ierr = CeedBasisGetInterp1D(basis, &interp_1d); CeedChkBackend(ierr);
8421617c04Sjeremylt         for (CeedInt d=0; d<dim; d++) {
852f86a920SJeremy L Thompson           ierr = CeedTensorContractApply(contract, pre, P, post, Q,
86d1d35e2fSjeremylt                                          interp_1d, t_mode, add&&(d==dim-1),
87dfe03796SJeremy L Thompson                                          d==0?u:tmp[d%2],
88dfe03796SJeremy L Thompson                                          d==dim-1?v:tmp[(d+1)%2]);
89e15f9bd0SJeremy L Thompson           CeedChkBackend(ierr);
9021617c04Sjeremylt           pre /= P;
9121617c04Sjeremylt           post *= Q;
9221617c04Sjeremylt         }
93dfe03796SJeremy L Thompson       }
94a2b73c81Sjeremylt     } break;
958d94b059Sjeremylt     // Evaluate the gradient to/from quadrature points
96a2b73c81Sjeremylt     case CEED_EVAL_GRAD: {
9721617c04Sjeremylt       // In CEED_NOTRANSPOSE mode:
98d1d35e2fSjeremylt       // u has shape [dim, num_comp, P^dim, num_elem], row-major layout
99d1d35e2fSjeremylt       // v has shape [dim, num_comp, Q^dim, num_elem], row-major layout
10021617c04Sjeremylt       // In CEED_TRANSPOSE mode, the sizes of u and v are switched.
101d1d35e2fSjeremylt       CeedInt P = P_1d, Q = Q_1d;
102d1d35e2fSjeremylt       if (t_mode == CEED_TRANSPOSE) {
103d1d35e2fSjeremylt         P = Q_1d, Q = Q_1d;
10421617c04Sjeremylt       }
10584a01de5SJeremy L Thompson       CeedBasis_Ref *impl;
106e15f9bd0SJeremy L Thompson       ierr = CeedBasisGetData(basis, &impl); CeedChkBackend(ierr);
107d1d35e2fSjeremylt       CeedInt pre = num_comp*CeedIntPow(P, dim-1), post = num_elem;
108d1d35e2fSjeremylt       const CeedScalar *interp_1d;
109d1d35e2fSjeremylt       ierr = CeedBasisGetInterp1D(basis, &interp_1d); CeedChkBackend(ierr);
1108c1105f8SJeremy L Thompson       if (impl->collo_grad_1d) {
111d1d35e2fSjeremylt         CeedScalar tmp[2][num_elem*num_comp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
112d1d35e2fSjeremylt         CeedScalar interp[num_elem*num_comp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
11384a01de5SJeremy L Thompson         // Interpolate to quadrature points (NoTranspose)
11484a01de5SJeremy L Thompson         //  or Grad to quadrature points (Transpose)
11521617c04Sjeremylt         for (CeedInt d=0; d<dim; d++) {
1162f86a920SJeremy L Thompson           ierr = CeedTensorContractApply(contract, pre, P, post, Q,
117d1d35e2fSjeremylt                                          (t_mode == CEED_NOTRANSPOSE
118d1d35e2fSjeremylt                                           ? interp_1d
1198c1105f8SJeremy L Thompson                                           : impl->collo_grad_1d),
120d1d35e2fSjeremylt                                          t_mode, add&&(d>0),
121d1d35e2fSjeremylt                                          (t_mode == CEED_NOTRANSPOSE
12284a01de5SJeremy L Thompson                                           ? (d==0?u:tmp[d%2])
123d1d35e2fSjeremylt                                           : u + d*num_qpts*num_comp*num_elem),
124d1d35e2fSjeremylt                                          (t_mode == CEED_NOTRANSPOSE
12584a01de5SJeremy L Thompson                                           ? (d==dim-1?interp:tmp[(d+1)%2])
12684a01de5SJeremy L Thompson                                           : interp));
127e15f9bd0SJeremy L Thompson           CeedChkBackend(ierr);
12821617c04Sjeremylt           pre /= P;
12921617c04Sjeremylt           post *= Q;
13021617c04Sjeremylt         }
13184a01de5SJeremy L Thompson         // Grad to quadrature points (NoTranspose)
1328795c945Sjeremylt         //  or Interpolate to nodes (Transpose)
133d1d35e2fSjeremylt         P = Q_1d, Q = Q_1d;
134d1d35e2fSjeremylt         if (t_mode == CEED_TRANSPOSE) {
135d1d35e2fSjeremylt           P = Q_1d, Q = P_1d;
13684a01de5SJeremy L Thompson         }
137d1d35e2fSjeremylt         pre = num_comp*CeedIntPow(P, dim-1), post = num_elem;
13884a01de5SJeremy L Thompson         for (CeedInt d=0; d<dim; d++) {
1392f86a920SJeremy L Thompson           ierr = CeedTensorContractApply(contract, pre, P, post, Q,
140d1d35e2fSjeremylt                                          (t_mode == CEED_NOTRANSPOSE
1418c1105f8SJeremy L Thompson                                           ? impl->collo_grad_1d
142d1d35e2fSjeremylt                                           : interp_1d),
143d1d35e2fSjeremylt                                          t_mode, add&&(d==dim-1),
144d1d35e2fSjeremylt                                          (t_mode == CEED_NOTRANSPOSE
14584a01de5SJeremy L Thompson                                           ? interp
14684a01de5SJeremy L Thompson                                           : (d==0?interp:tmp[d%2])),
147d1d35e2fSjeremylt                                          (t_mode == CEED_NOTRANSPOSE
148d1d35e2fSjeremylt                                           ? v + d*num_qpts*num_comp*num_elem
14984a01de5SJeremy L Thompson                                           : (d==dim-1?v:tmp[(d+1)%2])));
150e15f9bd0SJeremy L Thompson           CeedChkBackend(ierr);
15184a01de5SJeremy L Thompson           pre /= P;
15284a01de5SJeremy L Thompson           post *= Q;
15321617c04Sjeremylt         }
1548c1105f8SJeremy L Thompson       } else if (impl->has_collo_interp) { // Qpts collocated with nodes
155d1d35e2fSjeremylt         const CeedScalar *grad_1d;
156d1d35e2fSjeremylt         ierr = CeedBasisGetGrad1D(basis, &grad_1d); CeedChkBackend(ierr);
157dfe03796SJeremy L Thompson 
158dfe03796SJeremy L Thompson         // Dim contractions, identity in other directions
159d1d35e2fSjeremylt         CeedInt pre = num_comp*CeedIntPow(P, dim-1), post = num_elem;
160c6158135Sjeremylt         for (CeedInt d=0; d<dim; d++) {
161dfe03796SJeremy L Thompson           ierr = CeedTensorContractApply(contract, pre, P, post, Q,
162d1d35e2fSjeremylt                                          grad_1d, t_mode, add&&(d>0),
163d1d35e2fSjeremylt                                          t_mode == CEED_NOTRANSPOSE
164d1d35e2fSjeremylt                                          ? u : u+d*num_comp*num_qpts*num_elem,
165d1d35e2fSjeremylt                                          t_mode == CEED_TRANSPOSE
166d1d35e2fSjeremylt                                          ? v : v+d*num_comp*num_qpts*num_elem);
167e15f9bd0SJeremy L Thompson           CeedChkBackend(ierr);
168c6158135Sjeremylt           pre /= P;
169c6158135Sjeremylt           post *= Q;
170dfe03796SJeremy L Thompson         }
171a7bd39daSjeremylt       } else { // Underintegration, P > Q
172d1d35e2fSjeremylt         const CeedScalar *grad_1d;
173d1d35e2fSjeremylt         ierr = CeedBasisGetGrad1D(basis, &grad_1d); CeedChkBackend(ierr);
174a7bd39daSjeremylt 
175d1d35e2fSjeremylt         if (t_mode == CEED_TRANSPOSE) {
176d1d35e2fSjeremylt           P = Q_1d, Q = P_1d;
177a7bd39daSjeremylt         }
178d1d35e2fSjeremylt         CeedScalar tmp[2][num_elem*num_comp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
179a7bd39daSjeremylt 
180a7bd39daSjeremylt         // Dim**2 contractions, apply grad when pass == dim
181a7bd39daSjeremylt         for (CeedInt p=0; p<dim; p++) {
182d1d35e2fSjeremylt           CeedInt pre = num_comp*CeedIntPow(P, dim-1), post = num_elem;
183a7bd39daSjeremylt           for (CeedInt d=0; d<dim; d++) {
184a7bd39daSjeremylt             ierr = CeedTensorContractApply(contract, pre, P, post, Q,
185d1d35e2fSjeremylt                                            (p==d)? grad_1d : interp_1d,
186d1d35e2fSjeremylt                                            t_mode, add&&(d==dim-1),
187a7bd39daSjeremylt                                            (d == 0
188d1d35e2fSjeremylt                                             ? (t_mode == CEED_NOTRANSPOSE
189d1d35e2fSjeremylt                                                ? u : u+p*num_comp*num_qpts*num_elem)
190a7bd39daSjeremylt                                             : tmp[d%2]),
191a7bd39daSjeremylt                                            (d == dim-1
192d1d35e2fSjeremylt                                             ? (t_mode == CEED_TRANSPOSE
193d1d35e2fSjeremylt                                                ? v : v+p*num_comp*num_qpts*num_elem)
194a7bd39daSjeremylt                                             : tmp[(d+1)%2]));
195e15f9bd0SJeremy L Thompson             CeedChkBackend(ierr);
196a7bd39daSjeremylt             pre /= P;
197a7bd39daSjeremylt             post *= Q;
198a7bd39daSjeremylt           }
199a7bd39daSjeremylt         }
200a7bd39daSjeremylt       }
201a2b73c81Sjeremylt     } break;
2028d94b059Sjeremylt     // Retrieve interpolation weights
203a2b73c81Sjeremylt     case CEED_EVAL_WEIGHT: {
204d1d35e2fSjeremylt       if (t_mode == CEED_TRANSPOSE)
205c042f62fSJeremy L Thompson         // LCOV_EXCL_START
206e15f9bd0SJeremy L Thompson         return CeedError(ceed, CEED_ERROR_BACKEND,
20721617c04Sjeremylt                          "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE");
208c042f62fSJeremy L Thompson       // LCOV_EXCL_STOP
209d1d35e2fSjeremylt       CeedInt Q = Q_1d;
210d1d35e2fSjeremylt       const CeedScalar *q_weight_1d;
211d1d35e2fSjeremylt       ierr = CeedBasisGetQWeights(basis, &q_weight_1d); CeedChkBackend(ierr);
21221617c04Sjeremylt       for (CeedInt d=0; d<dim; d++) {
213b5cf12eeSjeremylt         CeedInt pre = CeedIntPow(Q, dim-d-1), post = CeedIntPow(Q, d);
214a2b73c81Sjeremylt         for (CeedInt i=0; i<pre; i++)
215a2b73c81Sjeremylt           for (CeedInt j=0; j<Q; j++)
21684a01de5SJeremy L Thompson             for (CeedInt k=0; k<post; k++) {
217d1d35e2fSjeremylt               CeedScalar w = q_weight_1d[j]
218d1d35e2fSjeremylt                              * (d == 0 ? 1 : v[((i*Q + j)*post + k)*num_elem]);
219d1d35e2fSjeremylt               for (CeedInt e=0; e<num_elem; e++)
220d1d35e2fSjeremylt                 v[((i*Q + j)*post + k)*num_elem + e] = w;
22184a01de5SJeremy L Thompson             }
22221617c04Sjeremylt       }
223a2b73c81Sjeremylt     } break;
224c042f62fSJeremy L Thompson     // LCOV_EXCL_START
2258d94b059Sjeremylt     // Evaluate the divergence to/from the quadrature points
226a2b73c81Sjeremylt     case CEED_EVAL_DIV:
227e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_DIV not supported");
2288d94b059Sjeremylt     // Evaluate the curl to/from the quadrature points
229a2b73c81Sjeremylt     case CEED_EVAL_CURL:
230e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_CURL not supported");
2318d94b059Sjeremylt     // Take no action, BasisApply should not have been called
232a2b73c81Sjeremylt     case CEED_EVAL_NONE:
233e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_BACKEND,
2344b8bea3bSJed Brown                        "CEED_EVAL_NONE does not make sense in this context");
235c042f62fSJeremy L Thompson       // LCOV_EXCL_STOP
23621617c04Sjeremylt     }
237a8de75f0Sjeremylt   } else {
238a8de75f0Sjeremylt     // Non-tensor basis
239d1d35e2fSjeremylt     switch (eval_mode) {
24084a01de5SJeremy L Thompson     // Interpolate to/from quadrature points
241a8de75f0Sjeremylt     case CEED_EVAL_INTERP: {
242*50c301a5SRezgar Shakeri       CeedInt P = num_nodes, Q = Q_comp*num_qpts;
2436c58de82SJeremy L Thompson       const CeedScalar *interp;
244e15f9bd0SJeremy L Thompson       ierr = CeedBasisGetInterp(basis, &interp); CeedChkBackend(ierr);
245d1d35e2fSjeremylt       if (t_mode == CEED_TRANSPOSE) {
246*50c301a5SRezgar Shakeri         P = Q_comp*num_qpts; Q = num_nodes;
247a8de75f0Sjeremylt       }
248d1d35e2fSjeremylt       ierr = CeedTensorContractApply(contract, num_comp, P, num_elem, Q,
249d1d35e2fSjeremylt                                      interp, t_mode, add, u, v);
250e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
251a8de75f0Sjeremylt     }
252a8de75f0Sjeremylt     break;
25384a01de5SJeremy L Thompson     // Evaluate the gradient to/from quadrature points
254a8de75f0Sjeremylt     case CEED_EVAL_GRAD: {
255d1d35e2fSjeremylt       CeedInt P = num_nodes, Q = num_qpts;
256d1d35e2fSjeremylt       CeedInt dim_stride = num_qpts * num_comp * num_elem;
257d1d35e2fSjeremylt       CeedInt grad_stride = num_qpts * num_nodes;
2586c58de82SJeremy L Thompson       const CeedScalar *grad;
259e15f9bd0SJeremy L Thompson       ierr = CeedBasisGetGrad(basis, &grad); CeedChkBackend(ierr);
260d1d35e2fSjeremylt       if (t_mode == CEED_TRANSPOSE) {
261d1d35e2fSjeremylt         P = num_qpts; Q = num_nodes;
262475a782bSnbeams         for (CeedInt d = 0; d < dim; d++) {
263d1d35e2fSjeremylt           ierr = CeedTensorContractApply(contract, num_comp, P, num_elem, Q,
264d1d35e2fSjeremylt                                          grad + d * grad_stride, t_mode, add,
265d1d35e2fSjeremylt                                          u + d * dim_stride, v); CeedChkBackend(ierr);
266475a782bSnbeams         }
267475a782bSnbeams       } else {
268475a782bSnbeams         for (CeedInt d = 0; d < dim; d++) {
269d1d35e2fSjeremylt           ierr = CeedTensorContractApply(contract, num_comp, P, num_elem, Q,
270d1d35e2fSjeremylt                                          grad + d * grad_stride, t_mode, add,
271d1d35e2fSjeremylt                                          u, v + d * dim_stride); CeedChkBackend(ierr);
272475a782bSnbeams         }
273475a782bSnbeams       }
274a8de75f0Sjeremylt     }
275a8de75f0Sjeremylt     break;
27684a01de5SJeremy L Thompson     // Retrieve interpolation weights
277a8de75f0Sjeremylt     case CEED_EVAL_WEIGHT: {
278d1d35e2fSjeremylt       if (t_mode == CEED_TRANSPOSE)
279c042f62fSJeremy L Thompson         // LCOV_EXCL_START
280e15f9bd0SJeremy L Thompson         return CeedError(ceed, CEED_ERROR_BACKEND,
281a8de75f0Sjeremylt                          "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE");
282c042f62fSJeremy L Thompson       // LCOV_EXCL_STOP
283d1d35e2fSjeremylt       const CeedScalar *q_weight;
284d1d35e2fSjeremylt       ierr = CeedBasisGetQWeights(basis, &q_weight); CeedChkBackend(ierr);
285d1d35e2fSjeremylt       for (CeedInt i=0; i<num_qpts; i++)
286d1d35e2fSjeremylt         for (CeedInt e=0; e<num_elem; e++)
287d1d35e2fSjeremylt           v[i*num_elem + e] = q_weight[i];
288a8de75f0Sjeremylt     } break;
28984a01de5SJeremy L Thompson     // Evaluate the divergence to/from the quadrature points
290*50c301a5SRezgar Shakeri     case CEED_EVAL_DIV: {
291*50c301a5SRezgar Shakeri       CeedInt P = num_nodes, Q = num_qpts;
292*50c301a5SRezgar Shakeri       const CeedScalar *div;
293*50c301a5SRezgar Shakeri       ierr = CeedBasisGetDiv(basis, &div); CeedChkBackend(ierr);
294*50c301a5SRezgar Shakeri       if (t_mode == CEED_TRANSPOSE) {
295*50c301a5SRezgar Shakeri         P = num_qpts; Q = num_nodes;
296*50c301a5SRezgar Shakeri       }
297*50c301a5SRezgar Shakeri       ierr = CeedTensorContractApply(contract, num_comp, P, num_elem, Q,
298*50c301a5SRezgar Shakeri                                      div, t_mode, add, u, v);
299*50c301a5SRezgar Shakeri       CeedChkBackend(ierr);
300*50c301a5SRezgar Shakeri     } break;
301*50c301a5SRezgar Shakeri     // LCOV_EXCL_START
30284a01de5SJeremy L Thompson     // Evaluate the curl to/from the quadrature points
303a8de75f0Sjeremylt     case CEED_EVAL_CURL:
304e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_CURL not supported");
30584a01de5SJeremy L Thompson     // Take no action, BasisApply should not have been called
306a8de75f0Sjeremylt     case CEED_EVAL_NONE:
307e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_BACKEND,
308a8de75f0Sjeremylt                        "CEED_EVAL_NONE does not make sense in this context");
309c042f62fSJeremy L Thompson       // LCOV_EXCL_STOP
310a8de75f0Sjeremylt     }
311a8de75f0Sjeremylt   }
312a7b7f929Sjeremylt   if (U != CEED_VECTOR_NONE) {
313e15f9bd0SJeremy L Thompson     ierr = CeedVectorRestoreArrayRead(U, &u); CeedChkBackend(ierr);
314aedaa0e5Sjeremylt   }
315e15f9bd0SJeremy L Thompson   ierr = CeedVectorRestoreArray(V, &v); CeedChkBackend(ierr);
316e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
31721617c04Sjeremylt }
31821617c04Sjeremylt 
319f10650afSjeremylt //------------------------------------------------------------------------------
320*50c301a5SRezgar Shakeri // Basis Create Non-Tensor H^1
321f10650afSjeremylt //------------------------------------------------------------------------------
322f10650afSjeremylt int CeedBasisCreateH1_Ref(CeedElemTopology topo, CeedInt dim,
323d1d35e2fSjeremylt                           CeedInt num_nodes, CeedInt num_qpts,
324f10650afSjeremylt                           const CeedScalar *interp,
325f10650afSjeremylt                           const CeedScalar *grad,
326d1d35e2fSjeremylt                           const CeedScalar *q_ref,
327d1d35e2fSjeremylt                           const CeedScalar *q_weight,
328f10650afSjeremylt                           CeedBasis basis) {
329f10650afSjeremylt   int ierr;
330f10650afSjeremylt   Ceed ceed;
331e15f9bd0SJeremy L Thompson   ierr = CeedBasisGetCeed(basis, &ceed); CeedChkBackend(ierr);
332f10650afSjeremylt 
333f10650afSjeremylt   Ceed parent;
334e15f9bd0SJeremy L Thompson   ierr = CeedGetParent(ceed, &parent); CeedChkBackend(ierr);
335f10650afSjeremylt   CeedTensorContract contract;
336e15f9bd0SJeremy L Thompson   ierr = CeedTensorContractCreate(parent, basis, &contract); CeedChkBackend(ierr);
33734359f16Sjeremylt   ierr = CeedBasisSetTensorContract(basis, contract); CeedChkBackend(ierr);
338f10650afSjeremylt 
339f10650afSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Apply",
340e15f9bd0SJeremy L Thompson                                 CeedBasisApply_Ref); CeedChkBackend(ierr);
341f10650afSjeremylt 
342e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
343f10650afSjeremylt }
344f10650afSjeremylt 
345f10650afSjeremylt //------------------------------------------------------------------------------
346*50c301a5SRezgar Shakeri // Basis Create Non-Tensor H(div)
347*50c301a5SRezgar Shakeri //------------------------------------------------------------------------------
348*50c301a5SRezgar Shakeri int CeedBasisCreateHdiv_Ref(CeedElemTopology topo, CeedInt dim,
349*50c301a5SRezgar Shakeri                             CeedInt num_nodes, CeedInt num_qpts,
350*50c301a5SRezgar Shakeri                             const CeedScalar *interp,
351*50c301a5SRezgar Shakeri                             const CeedScalar *div,
352*50c301a5SRezgar Shakeri                             const CeedScalar *q_ref,
353*50c301a5SRezgar Shakeri                             const CeedScalar *q_weight,
354*50c301a5SRezgar Shakeri                             CeedBasis basis) {
355*50c301a5SRezgar Shakeri   int ierr;
356*50c301a5SRezgar Shakeri   Ceed ceed;
357*50c301a5SRezgar Shakeri   ierr = CeedBasisGetCeed(basis, &ceed); CeedChkBackend(ierr);
358*50c301a5SRezgar Shakeri 
359*50c301a5SRezgar Shakeri   Ceed parent;
360*50c301a5SRezgar Shakeri   ierr = CeedGetParent(ceed, &parent); CeedChkBackend(ierr);
361*50c301a5SRezgar Shakeri   CeedTensorContract contract;
362*50c301a5SRezgar Shakeri   ierr = CeedTensorContractCreate(parent, basis, &contract); CeedChkBackend(ierr);
363*50c301a5SRezgar Shakeri   ierr = CeedBasisSetTensorContract(basis, contract); CeedChkBackend(ierr);
364*50c301a5SRezgar Shakeri 
365*50c301a5SRezgar Shakeri   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Apply",
366*50c301a5SRezgar Shakeri                                 CeedBasisApply_Ref); CeedChkBackend(ierr);
367*50c301a5SRezgar Shakeri 
368*50c301a5SRezgar Shakeri   return CEED_ERROR_SUCCESS;
369*50c301a5SRezgar Shakeri }
370*50c301a5SRezgar Shakeri 
371*50c301a5SRezgar Shakeri //------------------------------------------------------------------------------
372f10650afSjeremylt // Basis Destroy Tensor
373f10650afSjeremylt //------------------------------------------------------------------------------
37484a01de5SJeremy L Thompson static int CeedBasisDestroyTensor_Ref(CeedBasis basis) {
37584a01de5SJeremy L Thompson   int ierr;
3762f86a920SJeremy L Thompson 
37784a01de5SJeremy L Thompson   CeedBasis_Ref *impl;
378e15f9bd0SJeremy L Thompson   ierr = CeedBasisGetData(basis, &impl); CeedChkBackend(ierr);
3798c1105f8SJeremy L Thompson   ierr = CeedFree(&impl->collo_grad_1d); CeedChkBackend(ierr);
380e15f9bd0SJeremy L Thompson   ierr = CeedFree(&impl); CeedChkBackend(ierr);
38184a01de5SJeremy L Thompson 
382e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
38321617c04Sjeremylt }
38421617c04Sjeremylt 
385f10650afSjeremylt //------------------------------------------------------------------------------
386f10650afSjeremylt // Basis Create Tensor
387f10650afSjeremylt //------------------------------------------------------------------------------
388d1d35e2fSjeremylt int CeedBasisCreateTensorH1_Ref(CeedInt dim, CeedInt P_1d,
389d1d35e2fSjeremylt                                 CeedInt Q_1d, const CeedScalar *interp_1d,
390d1d35e2fSjeremylt                                 const CeedScalar *grad_1d,
391d1d35e2fSjeremylt                                 const CeedScalar *q_ref_1d,
392d1d35e2fSjeremylt                                 const CeedScalar *q_weight_1d,
39321617c04Sjeremylt                                 CeedBasis basis) {
394fe2413ffSjeremylt   int ierr;
395fe2413ffSjeremylt   Ceed ceed;
396e15f9bd0SJeremy L Thompson   ierr = CeedBasisGetCeed(basis, &ceed); CeedChkBackend(ierr);
39784a01de5SJeremy L Thompson   CeedBasis_Ref *impl;
398e15f9bd0SJeremy L Thompson   ierr = CeedCalloc(1, &impl); CeedChkBackend(ierr);
399dfe03796SJeremy L Thompson   // Check for collocated interp
400d1d35e2fSjeremylt   if (Q_1d == P_1d) {
401dfe03796SJeremy L Thompson     bool collocated = 1;
402d1d35e2fSjeremylt     for (CeedInt i=0; i<P_1d; i++) {
403d1d35e2fSjeremylt       collocated = collocated && (fabs(interp_1d[i+P_1d*i] - 1.0) < 1e-14);
404d1d35e2fSjeremylt       for (CeedInt j=0; j<P_1d; j++)
405dfe03796SJeremy L Thompson         if (j != i)
406d1d35e2fSjeremylt           collocated = collocated && (fabs(interp_1d[j+P_1d*i]) < 1e-14);
407dfe03796SJeremy L Thompson     }
4088c1105f8SJeremy L Thompson     impl->has_collo_interp = collocated;
409dfe03796SJeremy L Thompson   }
410dfe03796SJeremy L Thompson   // Calculate collocated grad
4118c1105f8SJeremy L Thompson   if (Q_1d >= P_1d && !impl->has_collo_interp) {
4128c1105f8SJeremy L Thompson     ierr = CeedMalloc(Q_1d*Q_1d, &impl->collo_grad_1d); CeedChkBackend(ierr);
4138c1105f8SJeremy L Thompson     ierr = CeedBasisGetCollocatedGrad(basis, impl->collo_grad_1d);
414e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
415a7bd39daSjeremylt   }
416e15f9bd0SJeremy L Thompson   ierr = CeedBasisSetData(basis, impl); CeedChkBackend(ierr);
417fe2413ffSjeremylt 
4182f86a920SJeremy L Thompson   Ceed parent;
419e15f9bd0SJeremy L Thompson   ierr = CeedGetParent(ceed, &parent); CeedChkBackend(ierr);
4202f86a920SJeremy L Thompson   CeedTensorContract contract;
421e15f9bd0SJeremy L Thompson   ierr = CeedTensorContractCreate(parent, basis, &contract); CeedChkBackend(ierr);
42234359f16Sjeremylt   ierr = CeedBasisSetTensorContract(basis, contract); CeedChkBackend(ierr);
4232f86a920SJeremy L Thompson 
424fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Apply",
425e15f9bd0SJeremy L Thompson                                 CeedBasisApply_Ref); CeedChkBackend(ierr);
426fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Destroy",
427e15f9bd0SJeremy L Thompson                                 CeedBasisDestroyTensor_Ref); CeedChkBackend(ierr);
428e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
42921617c04Sjeremylt }
430a8de75f0Sjeremylt 
431f10650afSjeremylt //------------------------------------------------------------------------------
432