xref: /libCEED/rust/libceed-sys/c-src/backends/ref/ceed-ref-basis.c (revision db2becc9f302fe8eb3a32ace50ce3f3a5d42e6c4)
15aed82e4SJeremy L Thompson // Copyright (c) 2017-2024, Lawrence Livermore National Security, LLC and other CEED contributors.
23d8e8822SJeremy L Thompson // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
321617c04Sjeremylt //
43d8e8822SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause
521617c04Sjeremylt //
63d8e8822SJeremy L Thompson // This file is part of CEED:  http://github.com/ceed
721617c04Sjeremylt 
849aac155SJeremy L Thompson #include <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>
132b730f8bSJeremy L Thompson 
1421617c04Sjeremylt #include "ceed-ref.h"
1521617c04Sjeremylt 
16f10650afSjeremylt //------------------------------------------------------------------------------
17f10650afSjeremylt // Basis Apply
18f10650afSjeremylt //------------------------------------------------------------------------------
19*db2becc9SJeremy L Thompson static int CeedBasisApplyCore_Ref(CeedBasis basis, bool apply_add, CeedInt num_elem, CeedTransposeMode t_mode, CeedEvalMode eval_mode, CeedVector U,
20*db2becc9SJeremy L Thompson                                   CeedVector V) {
214ce2993fSjeremylt   Ceed               ceed;
22*db2becc9SJeremy L Thompson   bool               is_tensor_basis, add = apply_add || (t_mode == CEED_TRANSPOSE);
23c4e3f59bSSebastian Grimberg   CeedInt            dim, num_comp, q_comp, num_nodes, num_qpts;
24ad70ee2cSJeremy L Thompson   const CeedScalar  *u;
25ad70ee2cSJeremy L Thompson   CeedScalar        *v;
26ad70ee2cSJeremy L Thompson   CeedTensorContract contract;
27ad70ee2cSJeremy L Thompson   CeedBasis_Ref     *impl;
28ad70ee2cSJeremy L Thompson 
29ad70ee2cSJeremy L Thompson   CeedCallBackend(CeedBasisGetCeed(basis, &ceed));
30ad70ee2cSJeremy L Thompson   CeedCallBackend(CeedBasisGetData(basis, &impl));
312b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisGetDimension(basis, &dim));
322b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisGetNumComponents(basis, &num_comp));
33c4e3f59bSSebastian Grimberg   CeedCallBackend(CeedBasisGetNumQuadratureComponents(basis, eval_mode, &q_comp));
342b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisGetNumNodes(basis, &num_nodes));
352b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisGetNumQuadraturePoints(basis, &num_qpts));
362b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisGetTensorContract(basis, &contract));
376574a04fSJeremy L Thompson   if (U != CEED_VECTOR_NONE) CeedCallBackend(CeedVectorGetArrayRead(U, CEED_MEM_HOST, &u));
386574a04fSJeremy L Thompson   else CeedCheck(eval_mode == CEED_EVAL_WEIGHT, ceed, CEED_ERROR_BACKEND, "An input vector is required for this CeedEvalMode");
398d94b059Sjeremylt   // Clear v if operating in transpose
40*db2becc9SJeremy L Thompson   if (apply_add) CeedCallBackend(CeedVectorGetArray(V, CEED_MEM_HOST, &v));
41*db2becc9SJeremy L Thompson   else CeedCallBackend(CeedVectorGetArrayWrite(V, CEED_MEM_HOST, &v));
42ad70ee2cSJeremy L Thompson 
43*db2becc9SJeremy L Thompson   if (t_mode == CEED_TRANSPOSE && !apply_add) {
44*db2becc9SJeremy L Thompson     CeedSize len;
45*db2becc9SJeremy L Thompson 
46*db2becc9SJeremy L Thompson     CeedCallBackend(CeedVectorGetLength(V, &len));
47*db2becc9SJeremy L Thompson     for (CeedInt i = 0; i < len; i++) v[i] = 0.0;
4821617c04Sjeremylt   }
49ad70ee2cSJeremy L Thompson 
506402da51SJeremy L Thompson   CeedCallBackend(CeedBasisIsTensor(basis, &is_tensor_basis));
516402da51SJeremy L Thompson   if (is_tensor_basis) {
52c4e3f59bSSebastian Grimberg     // Tensor basis
53d1d35e2fSjeremylt     CeedInt P_1d, Q_1d;
54ad70ee2cSJeremy L Thompson 
552b730f8bSJeremy L Thompson     CeedCallBackend(CeedBasisGetNumNodes1D(basis, &P_1d));
562b730f8bSJeremy L Thompson     CeedCallBackend(CeedBasisGetNumQuadraturePoints1D(basis, &Q_1d));
57d1d35e2fSjeremylt     switch (eval_mode) {
588d94b059Sjeremylt       // Interpolate to/from quadrature points
59a2b73c81Sjeremylt       case CEED_EVAL_INTERP: {
608c1105f8SJeremy L Thompson         if (impl->has_collo_interp) {
61d1d35e2fSjeremylt           memcpy(v, u, num_elem * num_comp * num_nodes * sizeof(u[0]));
62dfe03796SJeremy L Thompson         } else {
63d1d35e2fSjeremylt           CeedInt P = P_1d, Q = Q_1d;
64ad70ee2cSJeremy L Thompson 
65d1d35e2fSjeremylt           if (t_mode == CEED_TRANSPOSE) {
662b730f8bSJeremy L Thompson             P = Q_1d;
672b730f8bSJeremy L Thompson             Q = P_1d;
6821617c04Sjeremylt           }
69d1d35e2fSjeremylt           CeedInt           pre = num_comp * CeedIntPow(P, dim - 1), post = num_elem;
70d1d35e2fSjeremylt           CeedScalar        tmp[2][num_elem * num_comp * Q * CeedIntPow(P > Q ? P : Q, dim - 1)];
71d1d35e2fSjeremylt           const CeedScalar *interp_1d;
72ad70ee2cSJeremy L Thompson 
732b730f8bSJeremy L Thompson           CeedCallBackend(CeedBasisGetInterp1D(basis, &interp_1d));
7421617c04Sjeremylt           for (CeedInt d = 0; d < dim; d++) {
752b730f8bSJeremy L Thompson             CeedCallBackend(CeedTensorContractApply(contract, pre, P, post, Q, interp_1d, t_mode, add && (d == dim - 1), d == 0 ? u : tmp[d % 2],
762b730f8bSJeremy L Thompson                                                     d == dim - 1 ? v : tmp[(d + 1) % 2]));
7721617c04Sjeremylt             pre /= P;
7821617c04Sjeremylt             post *= Q;
7921617c04Sjeremylt           }
80dfe03796SJeremy L Thompson         }
81a2b73c81Sjeremylt       } break;
828d94b059Sjeremylt       // Evaluate the gradient to/from quadrature points
83a2b73c81Sjeremylt       case CEED_EVAL_GRAD: {
8421617c04Sjeremylt         // In CEED_NOTRANSPOSE mode:
85d1d35e2fSjeremylt         // u has shape [dim, num_comp, P^dim, num_elem], row-major layout
86d1d35e2fSjeremylt         // v has shape [dim, num_comp, Q^dim, num_elem], row-major layout
8721617c04Sjeremylt         // In CEED_TRANSPOSE mode, the sizes of u and v are switched.
88d1d35e2fSjeremylt         CeedInt P = P_1d, Q = Q_1d;
89ad70ee2cSJeremy L Thompson 
90d1d35e2fSjeremylt         if (t_mode == CEED_TRANSPOSE) {
911c66c397SJeremy L Thompson           P = Q_1d;
921c66c397SJeremy L Thompson           Q = Q_1d;
9321617c04Sjeremylt         }
94d1d35e2fSjeremylt         CeedInt           pre = num_comp * CeedIntPow(P, dim - 1), post = num_elem;
95d1d35e2fSjeremylt         const CeedScalar *interp_1d;
96ad70ee2cSJeremy L Thompson 
972b730f8bSJeremy L Thompson         CeedCallBackend(CeedBasisGetInterp1D(basis, &interp_1d));
988c1105f8SJeremy L Thompson         if (impl->collo_grad_1d) {
99d1d35e2fSjeremylt           CeedScalar tmp[2][num_elem * num_comp * Q * CeedIntPow(P > Q ? P : Q, dim - 1)];
100d1d35e2fSjeremylt           CeedScalar interp[num_elem * num_comp * Q * CeedIntPow(P > Q ? P : Q, dim - 1)];
101ad70ee2cSJeremy L Thompson 
10284a01de5SJeremy L Thompson           // Interpolate to quadrature points (NoTranspose)
10384a01de5SJeremy L Thompson           //  or Grad to quadrature points (Transpose)
10421617c04Sjeremylt           for (CeedInt d = 0; d < dim; d++) {
1052b730f8bSJeremy L Thompson             CeedCallBackend(CeedTensorContractApply(contract, pre, P, post, Q, (t_mode == CEED_NOTRANSPOSE ? interp_1d : impl->collo_grad_1d), t_mode,
106*db2becc9SJeremy L Thompson                                                     (t_mode == CEED_TRANSPOSE) && (d > 0),
107*db2becc9SJeremy L Thompson                                                     (t_mode == CEED_NOTRANSPOSE ? (d == 0 ? u : tmp[d % 2]) : &u[d * num_qpts * num_comp * num_elem]),
1082b730f8bSJeremy L Thompson                                                     (t_mode == CEED_NOTRANSPOSE ? (d == dim - 1 ? interp : tmp[(d + 1) % 2]) : interp)));
10921617c04Sjeremylt             pre /= P;
11021617c04Sjeremylt             post *= Q;
11121617c04Sjeremylt           }
11284a01de5SJeremy L Thompson           // Grad to quadrature points (NoTranspose)
1138795c945Sjeremylt           //  or Interpolate to nodes (Transpose)
114d1d35e2fSjeremylt           P = Q_1d, Q = Q_1d;
115d1d35e2fSjeremylt           if (t_mode == CEED_TRANSPOSE) {
1161c66c397SJeremy L Thompson             P = Q_1d;
1171c66c397SJeremy L Thompson             Q = P_1d;
11884a01de5SJeremy L Thompson           }
119d1d35e2fSjeremylt           pre = num_comp * CeedIntPow(P, dim - 1), post = num_elem;
12084a01de5SJeremy L Thompson           for (CeedInt d = 0; d < dim; d++) {
1212b730f8bSJeremy L Thompson             CeedCallBackend(CeedTensorContractApply(
122*db2becc9SJeremy L Thompson                 contract, pre, P, post, Q, (t_mode == CEED_NOTRANSPOSE ? impl->collo_grad_1d : interp_1d), t_mode,
123*db2becc9SJeremy L Thompson                 (t_mode == CEED_NOTRANSPOSE && apply_add) || (t_mode == CEED_TRANSPOSE && (d == dim - 1)),
1242b730f8bSJeremy L Thompson                 (t_mode == CEED_NOTRANSPOSE ? interp : (d == 0 ? interp : tmp[d % 2])),
125*db2becc9SJeremy L Thompson                 (t_mode == CEED_NOTRANSPOSE ? &v[d * num_qpts * num_comp * num_elem] : (d == dim - 1 ? v : tmp[(d + 1) % 2]))));
12684a01de5SJeremy L Thompson             pre /= P;
12784a01de5SJeremy L Thompson             post *= Q;
12821617c04Sjeremylt           }
1298c1105f8SJeremy L Thompson         } else if (impl->has_collo_interp) {  // Qpts collocated with nodes
130d1d35e2fSjeremylt           const CeedScalar *grad_1d;
131ad70ee2cSJeremy L Thompson 
1322b730f8bSJeremy L Thompson           CeedCallBackend(CeedBasisGetGrad1D(basis, &grad_1d));
133dfe03796SJeremy L Thompson 
134dfe03796SJeremy L Thompson           // Dim contractions, identity in other directions
135d1d35e2fSjeremylt           CeedInt pre = num_comp * CeedIntPow(P, dim - 1), post = num_elem;
136ad70ee2cSJeremy L Thompson 
137c6158135Sjeremylt           for (CeedInt d = 0; d < dim; d++) {
1382b730f8bSJeremy L Thompson             CeedCallBackend(CeedTensorContractApply(contract, pre, P, post, Q, grad_1d, t_mode, add && (d > 0),
139*db2becc9SJeremy L Thompson                                                     t_mode == CEED_NOTRANSPOSE ? u : &u[d * num_comp * num_qpts * num_elem],
140*db2becc9SJeremy L Thompson                                                     t_mode == CEED_TRANSPOSE ? v : &v[d * num_comp * num_qpts * num_elem]));
141c6158135Sjeremylt             pre /= P;
142c6158135Sjeremylt             post *= Q;
143dfe03796SJeremy L Thompson           }
144a7bd39daSjeremylt         } else {  // Underintegration, P > Q
145d1d35e2fSjeremylt           const CeedScalar *grad_1d;
146ad70ee2cSJeremy L Thompson 
1472b730f8bSJeremy L Thompson           CeedCallBackend(CeedBasisGetGrad1D(basis, &grad_1d));
148a7bd39daSjeremylt 
149d1d35e2fSjeremylt           if (t_mode == CEED_TRANSPOSE) {
1501c66c397SJeremy L Thompson             P = Q_1d;
1511c66c397SJeremy L Thompson             Q = P_1d;
152a7bd39daSjeremylt           }
153d1d35e2fSjeremylt           CeedScalar tmp[2][num_elem * num_comp * Q * CeedIntPow(P > Q ? P : Q, dim - 1)];
154a7bd39daSjeremylt 
155a7bd39daSjeremylt           // Dim**2 contractions, apply grad when pass == dim
156a7bd39daSjeremylt           for (CeedInt p = 0; p < dim; p++) {
157d1d35e2fSjeremylt             CeedInt pre = num_comp * CeedIntPow(P, dim - 1), post = num_elem;
158ad70ee2cSJeremy L Thompson 
159a7bd39daSjeremylt             for (CeedInt d = 0; d < dim; d++) {
1602b730f8bSJeremy L Thompson               CeedCallBackend(CeedTensorContractApply(
1612b730f8bSJeremy L Thompson                   contract, pre, P, post, Q, (p == d) ? grad_1d : interp_1d, t_mode, add && (d == dim - 1),
162*db2becc9SJeremy L Thompson                   (d == 0 ? (t_mode == CEED_NOTRANSPOSE ? u : &u[p * num_comp * num_qpts * num_elem]) : tmp[d % 2]),
163*db2becc9SJeremy L Thompson                   (d == dim - 1 ? (t_mode == CEED_TRANSPOSE ? v : &v[p * num_comp * num_qpts * num_elem]) : tmp[(d + 1) % 2])));
164a7bd39daSjeremylt               pre /= P;
165a7bd39daSjeremylt               post *= Q;
166a7bd39daSjeremylt             }
167a7bd39daSjeremylt           }
168a7bd39daSjeremylt         }
169a2b73c81Sjeremylt       } break;
1708d94b059Sjeremylt       // Retrieve interpolation weights
171a2b73c81Sjeremylt       case CEED_EVAL_WEIGHT: {
172d1d35e2fSjeremylt         CeedInt           Q = Q_1d;
173d1d35e2fSjeremylt         const CeedScalar *q_weight_1d;
174ad70ee2cSJeremy L Thompson 
175ad70ee2cSJeremy L Thompson         CeedCheck(t_mode == CEED_NOTRANSPOSE, ceed, CEED_ERROR_BACKEND, "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE");
1762b730f8bSJeremy L Thompson         CeedCallBackend(CeedBasisGetQWeights(basis, &q_weight_1d));
17721617c04Sjeremylt         for (CeedInt d = 0; d < dim; d++) {
178b5cf12eeSjeremylt           CeedInt pre = CeedIntPow(Q, dim - d - 1), post = CeedIntPow(Q, d);
179ad70ee2cSJeremy L Thompson 
1802b730f8bSJeremy L Thompson           for (CeedInt i = 0; i < pre; i++) {
1812b730f8bSJeremy L Thompson             for (CeedInt j = 0; j < Q; j++) {
18284a01de5SJeremy L Thompson               for (CeedInt k = 0; k < post; k++) {
183ad70ee2cSJeremy L Thompson                 const CeedScalar w = q_weight_1d[j] * (d == 0 ? 1 : v[((i * Q + j) * post + k) * num_elem]);
184ad70ee2cSJeremy L Thompson 
1852b730f8bSJeremy L Thompson                 for (CeedInt e = 0; e < num_elem; e++) v[((i * Q + j) * post + k) * num_elem + e] = w;
1862b730f8bSJeremy L Thompson               }
1872b730f8bSJeremy L Thompson             }
18884a01de5SJeremy L Thompson           }
18921617c04Sjeremylt         }
190a2b73c81Sjeremylt       } break;
191c042f62fSJeremy L Thompson       // LCOV_EXCL_START
192a2b73c81Sjeremylt       case CEED_EVAL_DIV:
193a2b73c81Sjeremylt       case CEED_EVAL_CURL:
194bcbe1c99SJeremy L Thompson         return CeedError(ceed, CEED_ERROR_BACKEND, "%s not supported", CeedEvalModes[eval_mode]);
195a2b73c81Sjeremylt       case CEED_EVAL_NONE:
1962b730f8bSJeremy L Thompson         return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_NONE does not make sense in this context");
197c042f62fSJeremy L Thompson         // LCOV_EXCL_STOP
19821617c04Sjeremylt     }
199a8de75f0Sjeremylt   } else {
200a8de75f0Sjeremylt     // Non-tensor basis
201c4e3f59bSSebastian Grimberg     CeedInt P = num_nodes, Q = num_qpts;
202ad70ee2cSJeremy L Thompson 
203d1d35e2fSjeremylt     switch (eval_mode) {
20484a01de5SJeremy L Thompson       // Interpolate to/from quadrature points
205a8de75f0Sjeremylt       case CEED_EVAL_INTERP: {
2066c58de82SJeremy L Thompson         const CeedScalar *interp;
207ad70ee2cSJeremy L Thompson 
2082b730f8bSJeremy L Thompson         CeedCallBackend(CeedBasisGetInterp(basis, &interp));
209c4e3f59bSSebastian Grimberg         CeedCallBackend(CeedTensorContractStridedApply(contract, num_comp, P, num_elem, q_comp, Q, interp, t_mode, add, u, v));
2102b730f8bSJeremy L Thompson       } break;
21184a01de5SJeremy L Thompson       // Evaluate the gradient to/from quadrature points
212a8de75f0Sjeremylt       case CEED_EVAL_GRAD: {
2136c58de82SJeremy L Thompson         const CeedScalar *grad;
214ad70ee2cSJeremy L Thompson 
2152b730f8bSJeremy L Thompson         CeedCallBackend(CeedBasisGetGrad(basis, &grad));
216c4e3f59bSSebastian Grimberg         CeedCallBackend(CeedTensorContractStridedApply(contract, num_comp, P, num_elem, q_comp, Q, grad, t_mode, add, u, v));
217c4e3f59bSSebastian Grimberg       } break;
218c4e3f59bSSebastian Grimberg       // Evaluate the divergence to/from the quadrature points
219c4e3f59bSSebastian Grimberg       case CEED_EVAL_DIV: {
220c4e3f59bSSebastian Grimberg         const CeedScalar *div;
221ad70ee2cSJeremy L Thompson 
222c4e3f59bSSebastian Grimberg         CeedCallBackend(CeedBasisGetDiv(basis, &div));
223c4e3f59bSSebastian Grimberg         CeedCallBackend(CeedTensorContractStridedApply(contract, num_comp, P, num_elem, q_comp, Q, div, t_mode, add, u, v));
224c4e3f59bSSebastian Grimberg       } break;
225c4e3f59bSSebastian Grimberg       // Evaluate the curl to/from the quadrature points
226c4e3f59bSSebastian Grimberg       case CEED_EVAL_CURL: {
227c4e3f59bSSebastian Grimberg         const CeedScalar *curl;
228ad70ee2cSJeremy L Thompson 
229c4e3f59bSSebastian Grimberg         CeedCallBackend(CeedBasisGetCurl(basis, &curl));
230c4e3f59bSSebastian Grimberg         CeedCallBackend(CeedTensorContractStridedApply(contract, num_comp, P, num_elem, q_comp, Q, curl, t_mode, add, u, v));
2312b730f8bSJeremy L Thompson       } break;
23284a01de5SJeremy L Thompson       // Retrieve interpolation weights
233a8de75f0Sjeremylt       case CEED_EVAL_WEIGHT: {
234d1d35e2fSjeremylt         const CeedScalar *q_weight;
235ad70ee2cSJeremy L Thompson 
236ad70ee2cSJeremy L Thompson         CeedCheck(t_mode == CEED_NOTRANSPOSE, ceed, CEED_ERROR_BACKEND, "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE");
2372b730f8bSJeremy L Thompson         CeedCallBackend(CeedBasisGetQWeights(basis, &q_weight));
2382b730f8bSJeremy L Thompson         for (CeedInt i = 0; i < num_qpts; i++) {
2392b730f8bSJeremy L Thompson           for (CeedInt e = 0; e < num_elem; e++) v[i * num_elem + e] = q_weight[i];
2402b730f8bSJeremy L Thompson         }
241a8de75f0Sjeremylt       } break;
24250c301a5SRezgar Shakeri       // LCOV_EXCL_START
243a8de75f0Sjeremylt       case CEED_EVAL_NONE:
2442b730f8bSJeremy L Thompson         return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_NONE does not make sense in this context");
245c042f62fSJeremy L Thompson         // LCOV_EXCL_STOP
246a8de75f0Sjeremylt     }
247a8de75f0Sjeremylt   }
248a7b7f929Sjeremylt   if (U != CEED_VECTOR_NONE) {
2492b730f8bSJeremy L Thompson     CeedCallBackend(CeedVectorRestoreArrayRead(U, &u));
250aedaa0e5Sjeremylt   }
2512b730f8bSJeremy L Thompson   CeedCallBackend(CeedVectorRestoreArray(V, &v));
252e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
25321617c04Sjeremylt }
25421617c04Sjeremylt 
255*db2becc9SJeremy L Thompson static int CeedBasisApply_Ref(CeedBasis basis, CeedInt num_elem, CeedTransposeMode t_mode, CeedEvalMode eval_mode, CeedVector U, CeedVector V) {
256*db2becc9SJeremy L Thompson   CeedCallBackend(CeedBasisApplyCore_Ref(basis, false, num_elem, t_mode, eval_mode, U, V));
257*db2becc9SJeremy L Thompson   return CEED_ERROR_SUCCESS;
258*db2becc9SJeremy L Thompson }
259*db2becc9SJeremy L Thompson 
260*db2becc9SJeremy L Thompson static int CeedBasisApplyAdd_Ref(CeedBasis basis, CeedInt num_elem, CeedTransposeMode t_mode, CeedEvalMode eval_mode, CeedVector U, CeedVector V) {
261*db2becc9SJeremy L Thompson   CeedCallBackend(CeedBasisApplyCore_Ref(basis, true, num_elem, t_mode, eval_mode, U, V));
262*db2becc9SJeremy L Thompson   return CEED_ERROR_SUCCESS;
263*db2becc9SJeremy L Thompson }
264*db2becc9SJeremy L Thompson 
265f10650afSjeremylt //------------------------------------------------------------------------------
266b2165e7aSSebastian Grimberg // Basis Destroy Tensor
267b2165e7aSSebastian Grimberg //------------------------------------------------------------------------------
268b2165e7aSSebastian Grimberg static int CeedBasisDestroyTensor_Ref(CeedBasis basis) {
269b2165e7aSSebastian Grimberg   CeedBasis_Ref *impl;
270ad70ee2cSJeremy L Thompson 
271b2165e7aSSebastian Grimberg   CeedCallBackend(CeedBasisGetData(basis, &impl));
272b2165e7aSSebastian Grimberg   CeedCallBackend(CeedFree(&impl->collo_grad_1d));
273b2165e7aSSebastian Grimberg   CeedCallBackend(CeedFree(&impl));
274b2165e7aSSebastian Grimberg   return CEED_ERROR_SUCCESS;
275b2165e7aSSebastian Grimberg }
276b2165e7aSSebastian Grimberg 
277b2165e7aSSebastian Grimberg //------------------------------------------------------------------------------
278b2165e7aSSebastian Grimberg // Basis Create Tensor
279b2165e7aSSebastian Grimberg //------------------------------------------------------------------------------
280b2165e7aSSebastian Grimberg int CeedBasisCreateTensorH1_Ref(CeedInt dim, CeedInt P_1d, CeedInt Q_1d, const CeedScalar *interp_1d, const CeedScalar *grad_1d,
281b2165e7aSSebastian Grimberg                                 const CeedScalar *q_ref_1d, const CeedScalar *q_weight_1d, CeedBasis basis) {
282ca735530SJeremy L Thompson   Ceed               ceed, ceed_parent;
283b2165e7aSSebastian Grimberg   CeedBasis_Ref     *impl;
284ad70ee2cSJeremy L Thompson   CeedTensorContract contract;
285ad70ee2cSJeremy L Thompson 
286ad70ee2cSJeremy L Thompson   CeedCallBackend(CeedBasisGetCeed(basis, &ceed));
287ca735530SJeremy L Thompson   CeedCallBackend(CeedGetParent(ceed, &ceed_parent));
288ad70ee2cSJeremy L Thompson 
289b2165e7aSSebastian Grimberg   CeedCallBackend(CeedCalloc(1, &impl));
290b2165e7aSSebastian Grimberg   // Check for collocated interp
291b2165e7aSSebastian Grimberg   if (Q_1d == P_1d) {
292ad70ee2cSJeremy L Thompson     bool has_collocated = true;
293ad70ee2cSJeremy L Thompson 
294b2165e7aSSebastian Grimberg     for (CeedInt i = 0; i < P_1d; i++) {
295ad70ee2cSJeremy L Thompson       has_collocated = has_collocated && (fabs(interp_1d[i + P_1d * i] - 1.0) < 1e-14);
296b2165e7aSSebastian Grimberg       for (CeedInt j = 0; j < P_1d; j++) {
297ad70ee2cSJeremy L Thompson         if (j != i) has_collocated = has_collocated && (fabs(interp_1d[j + P_1d * i]) < 1e-14);
298b2165e7aSSebastian Grimberg       }
299b2165e7aSSebastian Grimberg     }
300ad70ee2cSJeremy L Thompson     impl->has_collo_interp = has_collocated;
301b2165e7aSSebastian Grimberg   }
302b2165e7aSSebastian Grimberg   // Calculate collocated grad
303b2165e7aSSebastian Grimberg   if (Q_1d >= P_1d && !impl->has_collo_interp) {
304b2165e7aSSebastian Grimberg     CeedCallBackend(CeedMalloc(Q_1d * Q_1d, &impl->collo_grad_1d));
305b2165e7aSSebastian Grimberg     CeedCallBackend(CeedBasisGetCollocatedGrad(basis, impl->collo_grad_1d));
306b2165e7aSSebastian Grimberg   }
307b2165e7aSSebastian Grimberg   CeedCallBackend(CeedBasisSetData(basis, impl));
308b2165e7aSSebastian Grimberg 
309a71faab1SSebastian Grimberg   CeedCallBackend(CeedTensorContractCreate(ceed_parent, &contract));
310b2165e7aSSebastian Grimberg   CeedCallBackend(CeedBasisSetTensorContract(basis, contract));
311b2165e7aSSebastian Grimberg 
312b2165e7aSSebastian Grimberg   CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "Apply", CeedBasisApply_Ref));
313*db2becc9SJeremy L Thompson   CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "ApplyAdd", CeedBasisApplyAdd_Ref));
314b2165e7aSSebastian Grimberg   CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "Destroy", CeedBasisDestroyTensor_Ref));
315b2165e7aSSebastian Grimberg   return CEED_ERROR_SUCCESS;
316b2165e7aSSebastian Grimberg }
317b2165e7aSSebastian Grimberg 
318b2165e7aSSebastian Grimberg //------------------------------------------------------------------------------
31950c301a5SRezgar Shakeri // Basis Create Non-Tensor H^1
320f10650afSjeremylt //------------------------------------------------------------------------------
3212b730f8bSJeremy L Thompson int CeedBasisCreateH1_Ref(CeedElemTopology topo, CeedInt dim, CeedInt num_nodes, CeedInt num_qpts, const CeedScalar *interp, const CeedScalar *grad,
3222b730f8bSJeremy L Thompson                           const CeedScalar *q_ref, const CeedScalar *q_weight, CeedBasis basis) {
323ca735530SJeremy L Thompson   Ceed               ceed, ceed_parent;
324f10650afSjeremylt   CeedTensorContract contract;
325ad70ee2cSJeremy L Thompson 
326ad70ee2cSJeremy L Thompson   CeedCallBackend(CeedBasisGetCeed(basis, &ceed));
327ca735530SJeremy L Thompson   CeedCallBackend(CeedGetParent(ceed, &ceed_parent));
328ad70ee2cSJeremy L Thompson 
329a71faab1SSebastian Grimberg   CeedCallBackend(CeedTensorContractCreate(ceed_parent, &contract));
3302b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisSetTensorContract(basis, contract));
331f10650afSjeremylt 
3322b730f8bSJeremy L Thompson   CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "Apply", CeedBasisApply_Ref));
333*db2becc9SJeremy L Thompson   CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "ApplyAdd", CeedBasisApplyAdd_Ref));
334e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
335f10650afSjeremylt }
336f10650afSjeremylt 
337f10650afSjeremylt //------------------------------------------------------------------------------
33850c301a5SRezgar Shakeri // Basis Create Non-Tensor H(div)
33950c301a5SRezgar Shakeri //------------------------------------------------------------------------------
3402b730f8bSJeremy L Thompson int CeedBasisCreateHdiv_Ref(CeedElemTopology topo, CeedInt dim, CeedInt num_nodes, CeedInt num_qpts, const CeedScalar *interp, const CeedScalar *div,
3412b730f8bSJeremy L Thompson                             const CeedScalar *q_ref, const CeedScalar *q_weight, CeedBasis basis) {
342ca735530SJeremy L Thompson   Ceed               ceed, ceed_parent;
34350c301a5SRezgar Shakeri   CeedTensorContract contract;
344ad70ee2cSJeremy L Thompson 
345ad70ee2cSJeremy L Thompson   CeedCallBackend(CeedBasisGetCeed(basis, &ceed));
346ca735530SJeremy L Thompson   CeedCallBackend(CeedGetParent(ceed, &ceed_parent));
347ad70ee2cSJeremy L Thompson 
348a71faab1SSebastian Grimberg   CeedCallBackend(CeedTensorContractCreate(ceed_parent, &contract));
3492b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisSetTensorContract(basis, contract));
35050c301a5SRezgar Shakeri 
3512b730f8bSJeremy L Thompson   CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "Apply", CeedBasisApply_Ref));
352*db2becc9SJeremy L Thompson   CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "ApplyAdd", CeedBasisApplyAdd_Ref));
35350c301a5SRezgar Shakeri   return CEED_ERROR_SUCCESS;
35450c301a5SRezgar Shakeri }
35550c301a5SRezgar Shakeri 
35650c301a5SRezgar Shakeri //------------------------------------------------------------------------------
357c4e3f59bSSebastian Grimberg // Basis Create Non-Tensor H(curl)
358c4e3f59bSSebastian Grimberg //------------------------------------------------------------------------------
359c4e3f59bSSebastian Grimberg int CeedBasisCreateHcurl_Ref(CeedElemTopology topo, CeedInt dim, CeedInt num_nodes, CeedInt num_qpts, const CeedScalar *interp,
360c4e3f59bSSebastian Grimberg                              const CeedScalar *curl, const CeedScalar *q_ref, const CeedScalar *q_weight, CeedBasis basis) {
361ca735530SJeremy L Thompson   Ceed               ceed, ceed_parent;
362c4e3f59bSSebastian Grimberg   CeedTensorContract contract;
363ad70ee2cSJeremy L Thompson 
364ad70ee2cSJeremy L Thompson   CeedCallBackend(CeedBasisGetCeed(basis, &ceed));
365ca735530SJeremy L Thompson   CeedCallBackend(CeedGetParent(ceed, &ceed_parent));
366ad70ee2cSJeremy L Thompson 
367a71faab1SSebastian Grimberg   CeedCallBackend(CeedTensorContractCreate(ceed_parent, &contract));
368c4e3f59bSSebastian Grimberg   CeedCallBackend(CeedBasisSetTensorContract(basis, contract));
369c4e3f59bSSebastian Grimberg 
370c4e3f59bSSebastian Grimberg   CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "Apply", CeedBasisApply_Ref));
371*db2becc9SJeremy L Thompson   CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "ApplyAdd", CeedBasisApplyAdd_Ref));
372c4e3f59bSSebastian Grimberg   return CEED_ERROR_SUCCESS;
373c4e3f59bSSebastian Grimberg }
374c4e3f59bSSebastian Grimberg 
375c4e3f59bSSebastian Grimberg //------------------------------------------------------------------------------
376