xref: /libCEED/backends/ref/ceed-ref-basis.c (revision b2165e7a2e371018feedcb47974a027ed47e0487)
13d8e8822SJeremy L Thompson // Copyright (c) 2017-2022, 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 //------------------------------------------------------------------------------
192b730f8bSJeremy L Thompson static int CeedBasisApply_Ref(CeedBasis basis, CeedInt num_elem, CeedTransposeMode t_mode, CeedEvalMode eval_mode, CeedVector U, CeedVector V) {
204ce2993fSjeremylt   Ceed ceed;
212b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisGetCeed(basis, &ceed));
22c4e3f59bSSebastian Grimberg   CeedInt dim, num_comp, q_comp, num_nodes, num_qpts;
232b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisGetDimension(basis, &dim));
242b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisGetNumComponents(basis, &num_comp));
25c4e3f59bSSebastian Grimberg   CeedCallBackend(CeedBasisGetNumQuadratureComponents(basis, eval_mode, &q_comp));
262b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisGetNumNodes(basis, &num_nodes));
272b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisGetNumQuadraturePoints(basis, &num_qpts));
282f86a920SJeremy L Thompson   CeedTensorContract contract;
292b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisGetTensorContract(basis, &contract));
30d1d35e2fSjeremylt   const CeedInt     add = (t_mode == CEED_TRANSPOSE);
31aedaa0e5Sjeremylt   const CeedScalar *u;
32aedaa0e5Sjeremylt   CeedScalar       *v;
336574a04fSJeremy L Thompson   if (U != CEED_VECTOR_NONE) CeedCallBackend(CeedVectorGetArrayRead(U, CEED_MEM_HOST, &u));
346574a04fSJeremy L Thompson   else CeedCheck(eval_mode == CEED_EVAL_WEIGHT, ceed, CEED_ERROR_BACKEND, "An input vector is required for this CeedEvalMode");
352b730f8bSJeremy L Thompson   CeedCallBackend(CeedVectorGetArrayWrite(V, CEED_MEM_HOST, &v));
3621617c04Sjeremylt 
378d94b059Sjeremylt   // Clear v if operating in transpose
38d1d35e2fSjeremylt   if (t_mode == CEED_TRANSPOSE) {
39d1d35e2fSjeremylt     const CeedInt v_size = num_elem * num_comp * num_nodes;
402b730f8bSJeremy L Thompson     for (CeedInt i = 0; i < v_size; i++) v[i] = (CeedScalar)0.0;
4121617c04Sjeremylt   }
426402da51SJeremy L Thompson   bool is_tensor_basis;
436402da51SJeremy L Thompson   CeedCallBackend(CeedBasisIsTensor(basis, &is_tensor_basis));
446402da51SJeremy L Thompson   if (is_tensor_basis) {
45c4e3f59bSSebastian Grimberg     // Tensor basis
46d1d35e2fSjeremylt     CeedInt P_1d, Q_1d;
472b730f8bSJeremy L Thompson     CeedCallBackend(CeedBasisGetNumNodes1D(basis, &P_1d));
482b730f8bSJeremy L Thompson     CeedCallBackend(CeedBasisGetNumQuadraturePoints1D(basis, &Q_1d));
49d1d35e2fSjeremylt     switch (eval_mode) {
508d94b059Sjeremylt       // Interpolate to/from quadrature points
51a2b73c81Sjeremylt       case CEED_EVAL_INTERP: {
52dfe03796SJeremy L Thompson         CeedBasis_Ref *impl;
532b730f8bSJeremy L Thompson         CeedCallBackend(CeedBasisGetData(basis, &impl));
548c1105f8SJeremy L Thompson         if (impl->has_collo_interp) {
55d1d35e2fSjeremylt           memcpy(v, u, num_elem * num_comp * num_nodes * sizeof(u[0]));
56dfe03796SJeremy L Thompson         } else {
57d1d35e2fSjeremylt           CeedInt P = P_1d, Q = Q_1d;
58d1d35e2fSjeremylt           if (t_mode == CEED_TRANSPOSE) {
592b730f8bSJeremy L Thompson             P = Q_1d;
602b730f8bSJeremy L Thompson             Q = P_1d;
6121617c04Sjeremylt           }
62d1d35e2fSjeremylt           CeedInt           pre = num_comp * CeedIntPow(P, dim - 1), post = num_elem;
63d1d35e2fSjeremylt           CeedScalar        tmp[2][num_elem * num_comp * Q * CeedIntPow(P > Q ? P : Q, dim - 1)];
64d1d35e2fSjeremylt           const CeedScalar *interp_1d;
652b730f8bSJeremy L Thompson           CeedCallBackend(CeedBasisGetInterp1D(basis, &interp_1d));
6621617c04Sjeremylt           for (CeedInt d = 0; d < dim; d++) {
672b730f8bSJeremy L Thompson             CeedCallBackend(CeedTensorContractApply(contract, pre, P, post, Q, interp_1d, t_mode, add && (d == dim - 1), d == 0 ? u : tmp[d % 2],
682b730f8bSJeremy L Thompson                                                     d == dim - 1 ? v : tmp[(d + 1) % 2]));
6921617c04Sjeremylt             pre /= P;
7021617c04Sjeremylt             post *= Q;
7121617c04Sjeremylt           }
72dfe03796SJeremy L Thompson         }
73a2b73c81Sjeremylt       } break;
748d94b059Sjeremylt       // Evaluate the gradient to/from quadrature points
75a2b73c81Sjeremylt       case CEED_EVAL_GRAD: {
7621617c04Sjeremylt         // In CEED_NOTRANSPOSE mode:
77d1d35e2fSjeremylt         // u has shape [dim, num_comp, P^dim, num_elem], row-major layout
78d1d35e2fSjeremylt         // v has shape [dim, num_comp, Q^dim, num_elem], row-major layout
7921617c04Sjeremylt         // In CEED_TRANSPOSE mode, the sizes of u and v are switched.
80d1d35e2fSjeremylt         CeedInt P = P_1d, Q = Q_1d;
81d1d35e2fSjeremylt         if (t_mode == CEED_TRANSPOSE) {
82d1d35e2fSjeremylt           P = Q_1d, Q = Q_1d;
8321617c04Sjeremylt         }
8484a01de5SJeremy L Thompson         CeedBasis_Ref *impl;
852b730f8bSJeremy L Thompson         CeedCallBackend(CeedBasisGetData(basis, &impl));
86d1d35e2fSjeremylt         CeedInt           pre = num_comp * CeedIntPow(P, dim - 1), post = num_elem;
87d1d35e2fSjeremylt         const CeedScalar *interp_1d;
882b730f8bSJeremy L Thompson         CeedCallBackend(CeedBasisGetInterp1D(basis, &interp_1d));
898c1105f8SJeremy L Thompson         if (impl->collo_grad_1d) {
90d1d35e2fSjeremylt           CeedScalar tmp[2][num_elem * num_comp * Q * CeedIntPow(P > Q ? P : Q, dim - 1)];
91d1d35e2fSjeremylt           CeedScalar interp[num_elem * num_comp * Q * CeedIntPow(P > Q ? P : Q, dim - 1)];
9284a01de5SJeremy L Thompson           // Interpolate to quadrature points (NoTranspose)
9384a01de5SJeremy L Thompson           //  or Grad to quadrature points (Transpose)
9421617c04Sjeremylt           for (CeedInt d = 0; d < dim; d++) {
952b730f8bSJeremy L Thompson             CeedCallBackend(CeedTensorContractApply(contract, pre, P, post, Q, (t_mode == CEED_NOTRANSPOSE ? interp_1d : impl->collo_grad_1d), t_mode,
962b730f8bSJeremy L Thompson                                                     add && (d > 0),
972b730f8bSJeremy L Thompson                                                     (t_mode == CEED_NOTRANSPOSE ? (d == 0 ? u : tmp[d % 2]) : u + d * num_qpts * num_comp * num_elem),
982b730f8bSJeremy L Thompson                                                     (t_mode == CEED_NOTRANSPOSE ? (d == dim - 1 ? interp : tmp[(d + 1) % 2]) : interp)));
9921617c04Sjeremylt             pre /= P;
10021617c04Sjeremylt             post *= Q;
10121617c04Sjeremylt           }
10284a01de5SJeremy L Thompson           // Grad to quadrature points (NoTranspose)
1038795c945Sjeremylt           //  or Interpolate to nodes (Transpose)
104d1d35e2fSjeremylt           P = Q_1d, Q = Q_1d;
105d1d35e2fSjeremylt           if (t_mode == CEED_TRANSPOSE) {
106d1d35e2fSjeremylt             P = Q_1d, Q = P_1d;
10784a01de5SJeremy L Thompson           }
108d1d35e2fSjeremylt           pre = num_comp * CeedIntPow(P, dim - 1), post = num_elem;
10984a01de5SJeremy L Thompson           for (CeedInt d = 0; d < dim; d++) {
1102b730f8bSJeremy L Thompson             CeedCallBackend(CeedTensorContractApply(
1112b730f8bSJeremy L Thompson                 contract, pre, P, post, Q, (t_mode == CEED_NOTRANSPOSE ? impl->collo_grad_1d : interp_1d), t_mode, add && (d == dim - 1),
1122b730f8bSJeremy L Thompson                 (t_mode == CEED_NOTRANSPOSE ? interp : (d == 0 ? interp : tmp[d % 2])),
1132b730f8bSJeremy L Thompson                 (t_mode == CEED_NOTRANSPOSE ? v + d * num_qpts * num_comp * num_elem : (d == dim - 1 ? v : tmp[(d + 1) % 2]))));
11484a01de5SJeremy L Thompson             pre /= P;
11584a01de5SJeremy L Thompson             post *= Q;
11621617c04Sjeremylt           }
1178c1105f8SJeremy L Thompson         } else if (impl->has_collo_interp) {  // Qpts collocated with nodes
118d1d35e2fSjeremylt           const CeedScalar *grad_1d;
1192b730f8bSJeremy L Thompson           CeedCallBackend(CeedBasisGetGrad1D(basis, &grad_1d));
120dfe03796SJeremy L Thompson 
121dfe03796SJeremy L Thompson           // Dim contractions, identity in other directions
122d1d35e2fSjeremylt           CeedInt pre = num_comp * CeedIntPow(P, dim - 1), post = num_elem;
123c6158135Sjeremylt           for (CeedInt d = 0; d < dim; d++) {
1242b730f8bSJeremy L Thompson             CeedCallBackend(CeedTensorContractApply(contract, pre, P, post, Q, grad_1d, t_mode, add && (d > 0),
1252b730f8bSJeremy L Thompson                                                     t_mode == CEED_NOTRANSPOSE ? u : u + d * num_comp * num_qpts * num_elem,
1262b730f8bSJeremy L Thompson                                                     t_mode == CEED_TRANSPOSE ? v : v + d * num_comp * num_qpts * num_elem));
127c6158135Sjeremylt             pre /= P;
128c6158135Sjeremylt             post *= Q;
129dfe03796SJeremy L Thompson           }
130a7bd39daSjeremylt         } else {  // Underintegration, P > Q
131d1d35e2fSjeremylt           const CeedScalar *grad_1d;
1322b730f8bSJeremy L Thompson           CeedCallBackend(CeedBasisGetGrad1D(basis, &grad_1d));
133a7bd39daSjeremylt 
134d1d35e2fSjeremylt           if (t_mode == CEED_TRANSPOSE) {
135d1d35e2fSjeremylt             P = Q_1d, Q = P_1d;
136a7bd39daSjeremylt           }
137d1d35e2fSjeremylt           CeedScalar tmp[2][num_elem * num_comp * Q * CeedIntPow(P > Q ? P : Q, dim - 1)];
138a7bd39daSjeremylt 
139a7bd39daSjeremylt           // Dim**2 contractions, apply grad when pass == dim
140a7bd39daSjeremylt           for (CeedInt p = 0; p < dim; p++) {
141d1d35e2fSjeremylt             CeedInt pre = num_comp * CeedIntPow(P, dim - 1), post = num_elem;
142a7bd39daSjeremylt             for (CeedInt d = 0; d < dim; d++) {
1432b730f8bSJeremy L Thompson               CeedCallBackend(CeedTensorContractApply(
1442b730f8bSJeremy L Thompson                   contract, pre, P, post, Q, (p == d) ? grad_1d : interp_1d, t_mode, add && (d == dim - 1),
1452b730f8bSJeremy L Thompson                   (d == 0 ? (t_mode == CEED_NOTRANSPOSE ? u : u + p * num_comp * num_qpts * num_elem) : tmp[d % 2]),
1462b730f8bSJeremy L Thompson                   (d == dim - 1 ? (t_mode == CEED_TRANSPOSE ? v : v + p * num_comp * num_qpts * num_elem) : tmp[(d + 1) % 2])));
147a7bd39daSjeremylt               pre /= P;
148a7bd39daSjeremylt               post *= Q;
149a7bd39daSjeremylt             }
150a7bd39daSjeremylt           }
151a7bd39daSjeremylt         }
152a2b73c81Sjeremylt       } break;
1538d94b059Sjeremylt       // Retrieve interpolation weights
154a2b73c81Sjeremylt       case CEED_EVAL_WEIGHT: {
1556574a04fSJeremy L Thompson         CeedCheck(t_mode == CEED_NOTRANSPOSE, ceed, CEED_ERROR_BACKEND, "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE");
156d1d35e2fSjeremylt         CeedInt           Q = Q_1d;
157d1d35e2fSjeremylt         const CeedScalar *q_weight_1d;
1582b730f8bSJeremy L Thompson         CeedCallBackend(CeedBasisGetQWeights(basis, &q_weight_1d));
15921617c04Sjeremylt         for (CeedInt d = 0; d < dim; d++) {
160b5cf12eeSjeremylt           CeedInt pre = CeedIntPow(Q, dim - d - 1), post = CeedIntPow(Q, d);
1612b730f8bSJeremy L Thompson           for (CeedInt i = 0; i < pre; i++) {
1622b730f8bSJeremy L Thompson             for (CeedInt j = 0; j < Q; j++) {
16384a01de5SJeremy L Thompson               for (CeedInt k = 0; k < post; k++) {
1642b730f8bSJeremy L Thompson                 CeedScalar w = q_weight_1d[j] * (d == 0 ? 1 : v[((i * Q + j) * post + k) * num_elem]);
1652b730f8bSJeremy L Thompson                 for (CeedInt e = 0; e < num_elem; e++) v[((i * Q + j) * post + k) * num_elem + e] = w;
1662b730f8bSJeremy L Thompson               }
1672b730f8bSJeremy L Thompson             }
16884a01de5SJeremy L Thompson           }
16921617c04Sjeremylt         }
170a2b73c81Sjeremylt       } break;
171c042f62fSJeremy L Thompson       // LCOV_EXCL_START
1728d94b059Sjeremylt       // Evaluate the divergence to/from the quadrature points
173a2b73c81Sjeremylt       case CEED_EVAL_DIV:
174e15f9bd0SJeremy L Thompson         return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_DIV not supported");
1758d94b059Sjeremylt       // Evaluate the curl to/from the quadrature points
176a2b73c81Sjeremylt       case CEED_EVAL_CURL:
177e15f9bd0SJeremy L Thompson         return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_CURL not supported");
1788d94b059Sjeremylt       // Take no action, BasisApply should not have been called
179a2b73c81Sjeremylt       case CEED_EVAL_NONE:
1802b730f8bSJeremy L Thompson         return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_NONE does not make sense in this context");
181c042f62fSJeremy L Thompson         // LCOV_EXCL_STOP
18221617c04Sjeremylt     }
183a8de75f0Sjeremylt   } else {
184a8de75f0Sjeremylt     // Non-tensor basis
185c4e3f59bSSebastian Grimberg     CeedInt P = num_nodes, Q = num_qpts;
186d1d35e2fSjeremylt     switch (eval_mode) {
18784a01de5SJeremy L Thompson       // Interpolate to/from quadrature points
188a8de75f0Sjeremylt       case CEED_EVAL_INTERP: {
1896c58de82SJeremy L Thompson         const CeedScalar *interp;
1902b730f8bSJeremy L Thompson         CeedCallBackend(CeedBasisGetInterp(basis, &interp));
191c4e3f59bSSebastian Grimberg         CeedCallBackend(CeedTensorContractStridedApply(contract, num_comp, P, num_elem, q_comp, Q, interp, t_mode, add, u, v));
1922b730f8bSJeremy L Thompson       } break;
19384a01de5SJeremy L Thompson       // Evaluate the gradient to/from quadrature points
194a8de75f0Sjeremylt       case CEED_EVAL_GRAD: {
1956c58de82SJeremy L Thompson         const CeedScalar *grad;
1962b730f8bSJeremy L Thompson         CeedCallBackend(CeedBasisGetGrad(basis, &grad));
197c4e3f59bSSebastian Grimberg         CeedCallBackend(CeedTensorContractStridedApply(contract, num_comp, P, num_elem, q_comp, Q, grad, t_mode, add, u, v));
198c4e3f59bSSebastian Grimberg       } break;
199c4e3f59bSSebastian Grimberg       // Evaluate the divergence to/from the quadrature points
200c4e3f59bSSebastian Grimberg       case CEED_EVAL_DIV: {
201c4e3f59bSSebastian Grimberg         const CeedScalar *div;
202c4e3f59bSSebastian Grimberg         CeedCallBackend(CeedBasisGetDiv(basis, &div));
203c4e3f59bSSebastian Grimberg         CeedCallBackend(CeedTensorContractStridedApply(contract, num_comp, P, num_elem, q_comp, Q, div, t_mode, add, u, v));
204c4e3f59bSSebastian Grimberg       } break;
205c4e3f59bSSebastian Grimberg       // Evaluate the curl to/from the quadrature points
206c4e3f59bSSebastian Grimberg       case CEED_EVAL_CURL: {
207c4e3f59bSSebastian Grimberg         const CeedScalar *curl;
208c4e3f59bSSebastian Grimberg         CeedCallBackend(CeedBasisGetCurl(basis, &curl));
209c4e3f59bSSebastian Grimberg         CeedCallBackend(CeedTensorContractStridedApply(contract, num_comp, P, num_elem, q_comp, Q, curl, t_mode, add, u, v));
2102b730f8bSJeremy L Thompson       } break;
21184a01de5SJeremy L Thompson       // Retrieve interpolation weights
212a8de75f0Sjeremylt       case CEED_EVAL_WEIGHT: {
2136574a04fSJeremy L Thompson         CeedCheck(t_mode == CEED_NOTRANSPOSE, ceed, CEED_ERROR_BACKEND, "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE");
214d1d35e2fSjeremylt         const CeedScalar *q_weight;
2152b730f8bSJeremy L Thompson         CeedCallBackend(CeedBasisGetQWeights(basis, &q_weight));
2162b730f8bSJeremy L Thompson         for (CeedInt i = 0; i < num_qpts; i++) {
2172b730f8bSJeremy L Thompson           for (CeedInt e = 0; e < num_elem; e++) v[i * num_elem + e] = q_weight[i];
2182b730f8bSJeremy L Thompson         }
219a8de75f0Sjeremylt       } break;
22050c301a5SRezgar Shakeri       // LCOV_EXCL_START
22184a01de5SJeremy L Thompson       // Take no action, BasisApply should not have been called
222a8de75f0Sjeremylt       case CEED_EVAL_NONE:
2232b730f8bSJeremy L Thompson         return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_NONE does not make sense in this context");
224c042f62fSJeremy L Thompson         // LCOV_EXCL_STOP
225a8de75f0Sjeremylt     }
226a8de75f0Sjeremylt   }
227a7b7f929Sjeremylt   if (U != CEED_VECTOR_NONE) {
2282b730f8bSJeremy L Thompson     CeedCallBackend(CeedVectorRestoreArrayRead(U, &u));
229aedaa0e5Sjeremylt   }
2302b730f8bSJeremy L Thompson   CeedCallBackend(CeedVectorRestoreArray(V, &v));
23102f1ab5cSSebastian Grimberg 
232e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
23321617c04Sjeremylt }
23421617c04Sjeremylt 
235f10650afSjeremylt //------------------------------------------------------------------------------
236*b2165e7aSSebastian Grimberg // Basis Destroy Tensor
237*b2165e7aSSebastian Grimberg //------------------------------------------------------------------------------
238*b2165e7aSSebastian Grimberg static int CeedBasisDestroyTensor_Ref(CeedBasis basis) {
239*b2165e7aSSebastian Grimberg   CeedBasis_Ref *impl;
240*b2165e7aSSebastian Grimberg   CeedCallBackend(CeedBasisGetData(basis, &impl));
241*b2165e7aSSebastian Grimberg   CeedCallBackend(CeedFree(&impl->collo_grad_1d));
242*b2165e7aSSebastian Grimberg   CeedCallBackend(CeedFree(&impl));
243*b2165e7aSSebastian Grimberg 
244*b2165e7aSSebastian Grimberg   return CEED_ERROR_SUCCESS;
245*b2165e7aSSebastian Grimberg }
246*b2165e7aSSebastian Grimberg 
247*b2165e7aSSebastian Grimberg //------------------------------------------------------------------------------
248*b2165e7aSSebastian Grimberg // Basis Create Tensor
249*b2165e7aSSebastian Grimberg //------------------------------------------------------------------------------
250*b2165e7aSSebastian Grimberg int CeedBasisCreateTensorH1_Ref(CeedInt dim, CeedInt P_1d, CeedInt Q_1d, const CeedScalar *interp_1d, const CeedScalar *grad_1d,
251*b2165e7aSSebastian Grimberg                                 const CeedScalar *q_ref_1d, const CeedScalar *q_weight_1d, CeedBasis basis) {
252*b2165e7aSSebastian Grimberg   Ceed ceed;
253*b2165e7aSSebastian Grimberg   CeedCallBackend(CeedBasisGetCeed(basis, &ceed));
254*b2165e7aSSebastian Grimberg   CeedBasis_Ref *impl;
255*b2165e7aSSebastian Grimberg   CeedCallBackend(CeedCalloc(1, &impl));
256*b2165e7aSSebastian Grimberg   // Check for collocated interp
257*b2165e7aSSebastian Grimberg   if (Q_1d == P_1d) {
258*b2165e7aSSebastian Grimberg     bool collocated = 1;
259*b2165e7aSSebastian Grimberg     for (CeedInt i = 0; i < P_1d; i++) {
260*b2165e7aSSebastian Grimberg       collocated = collocated && (fabs(interp_1d[i + P_1d * i] - 1.0) < 1e-14);
261*b2165e7aSSebastian Grimberg       for (CeedInt j = 0; j < P_1d; j++) {
262*b2165e7aSSebastian Grimberg         if (j != i) collocated = collocated && (fabs(interp_1d[j + P_1d * i]) < 1e-14);
263*b2165e7aSSebastian Grimberg       }
264*b2165e7aSSebastian Grimberg     }
265*b2165e7aSSebastian Grimberg     impl->has_collo_interp = collocated;
266*b2165e7aSSebastian Grimberg   }
267*b2165e7aSSebastian Grimberg   // Calculate collocated grad
268*b2165e7aSSebastian Grimberg   if (Q_1d >= P_1d && !impl->has_collo_interp) {
269*b2165e7aSSebastian Grimberg     CeedCallBackend(CeedMalloc(Q_1d * Q_1d, &impl->collo_grad_1d));
270*b2165e7aSSebastian Grimberg     CeedCallBackend(CeedBasisGetCollocatedGrad(basis, impl->collo_grad_1d));
271*b2165e7aSSebastian Grimberg   }
272*b2165e7aSSebastian Grimberg   CeedCallBackend(CeedBasisSetData(basis, impl));
273*b2165e7aSSebastian Grimberg 
274*b2165e7aSSebastian Grimberg   Ceed parent;
275*b2165e7aSSebastian Grimberg   CeedCallBackend(CeedGetParent(ceed, &parent));
276*b2165e7aSSebastian Grimberg   CeedTensorContract contract;
277*b2165e7aSSebastian Grimberg   CeedCallBackend(CeedTensorContractCreate(parent, basis, &contract));
278*b2165e7aSSebastian Grimberg   CeedCallBackend(CeedBasisSetTensorContract(basis, contract));
279*b2165e7aSSebastian Grimberg 
280*b2165e7aSSebastian Grimberg   CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "Apply", CeedBasisApply_Ref));
281*b2165e7aSSebastian Grimberg   CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "Destroy", CeedBasisDestroyTensor_Ref));
282*b2165e7aSSebastian Grimberg 
283*b2165e7aSSebastian Grimberg   return CEED_ERROR_SUCCESS;
284*b2165e7aSSebastian Grimberg }
285*b2165e7aSSebastian Grimberg 
286*b2165e7aSSebastian Grimberg //------------------------------------------------------------------------------
28750c301a5SRezgar Shakeri // Basis Create Non-Tensor H^1
288f10650afSjeremylt //------------------------------------------------------------------------------
2892b730f8bSJeremy L Thompson int CeedBasisCreateH1_Ref(CeedElemTopology topo, CeedInt dim, CeedInt num_nodes, CeedInt num_qpts, const CeedScalar *interp, const CeedScalar *grad,
2902b730f8bSJeremy L Thompson                           const CeedScalar *q_ref, const CeedScalar *q_weight, CeedBasis basis) {
291f10650afSjeremylt   Ceed ceed;
2922b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisGetCeed(basis, &ceed));
293f10650afSjeremylt 
294f10650afSjeremylt   Ceed parent;
2952b730f8bSJeremy L Thompson   CeedCallBackend(CeedGetParent(ceed, &parent));
296f10650afSjeremylt   CeedTensorContract contract;
2972b730f8bSJeremy L Thompson   CeedCallBackend(CeedTensorContractCreate(parent, basis, &contract));
2982b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisSetTensorContract(basis, contract));
299f10650afSjeremylt 
3002b730f8bSJeremy L Thompson   CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "Apply", CeedBasisApply_Ref));
301f10650afSjeremylt 
302e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
303f10650afSjeremylt }
304f10650afSjeremylt 
305f10650afSjeremylt //------------------------------------------------------------------------------
30650c301a5SRezgar Shakeri // Basis Create Non-Tensor H(div)
30750c301a5SRezgar Shakeri //------------------------------------------------------------------------------
3082b730f8bSJeremy L Thompson int CeedBasisCreateHdiv_Ref(CeedElemTopology topo, CeedInt dim, CeedInt num_nodes, CeedInt num_qpts, const CeedScalar *interp, const CeedScalar *div,
3092b730f8bSJeremy L Thompson                             const CeedScalar *q_ref, const CeedScalar *q_weight, CeedBasis basis) {
31050c301a5SRezgar Shakeri   Ceed ceed;
3112b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisGetCeed(basis, &ceed));
31250c301a5SRezgar Shakeri 
31350c301a5SRezgar Shakeri   Ceed parent;
3142b730f8bSJeremy L Thompson   CeedCallBackend(CeedGetParent(ceed, &parent));
31550c301a5SRezgar Shakeri   CeedTensorContract contract;
3162b730f8bSJeremy L Thompson   CeedCallBackend(CeedTensorContractCreate(parent, basis, &contract));
3172b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisSetTensorContract(basis, contract));
31850c301a5SRezgar Shakeri 
3192b730f8bSJeremy L Thompson   CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "Apply", CeedBasisApply_Ref));
32050c301a5SRezgar Shakeri 
32150c301a5SRezgar Shakeri   return CEED_ERROR_SUCCESS;
32250c301a5SRezgar Shakeri }
32350c301a5SRezgar Shakeri 
32450c301a5SRezgar Shakeri //------------------------------------------------------------------------------
325c4e3f59bSSebastian Grimberg // Basis Create Non-Tensor H(curl)
326c4e3f59bSSebastian Grimberg //------------------------------------------------------------------------------
327c4e3f59bSSebastian Grimberg int CeedBasisCreateHcurl_Ref(CeedElemTopology topo, CeedInt dim, CeedInt num_nodes, CeedInt num_qpts, const CeedScalar *interp,
328c4e3f59bSSebastian Grimberg                              const CeedScalar *curl, const CeedScalar *q_ref, const CeedScalar *q_weight, CeedBasis basis) {
329c4e3f59bSSebastian Grimberg   Ceed ceed;
330c4e3f59bSSebastian Grimberg   CeedCallBackend(CeedBasisGetCeed(basis, &ceed));
331c4e3f59bSSebastian Grimberg 
332c4e3f59bSSebastian Grimberg   Ceed parent;
333c4e3f59bSSebastian Grimberg   CeedCallBackend(CeedGetParent(ceed, &parent));
334c4e3f59bSSebastian Grimberg   CeedTensorContract contract;
335c4e3f59bSSebastian Grimberg   CeedCallBackend(CeedTensorContractCreate(parent, basis, &contract));
336c4e3f59bSSebastian Grimberg   CeedCallBackend(CeedBasisSetTensorContract(basis, contract));
337c4e3f59bSSebastian Grimberg 
338c4e3f59bSSebastian Grimberg   CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "Apply", CeedBasisApply_Ref));
339c4e3f59bSSebastian Grimberg 
340c4e3f59bSSebastian Grimberg   return CEED_ERROR_SUCCESS;
341c4e3f59bSSebastian Grimberg }
342c4e3f59bSSebastian Grimberg 
343c4e3f59bSSebastian Grimberg //------------------------------------------------------------------------------
344