xref: /libCEED/rust/libceed-sys/c-src/backends/ref/ceed-ref-basis.c (revision 49aac155e7a09736f56fb3abac0f57dab29f7cbf)
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 
8*49aac155SJeremy 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));
2250c301a5SRezgar Shakeri   CeedInt dim, num_comp, num_nodes, num_qpts, Q_comp;
232b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisGetDimension(basis, &dim));
242b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisGetNumComponents(basis, &num_comp));
252b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisGetNumNodes(basis, &num_nodes));
262b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisGetNumQuadraturePoints(basis, &num_qpts));
272b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisGetNumQuadratureComponents(basis, &Q_comp));
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;
33a7b7f929Sjeremylt   if (U != CEED_VECTOR_NONE) {
342b730f8bSJeremy L Thompson     CeedCallBackend(CeedVectorGetArrayRead(U, CEED_MEM_HOST, &u));
35d1d35e2fSjeremylt   } else if (eval_mode != CEED_EVAL_WEIGHT) {
36c042f62fSJeremy L Thompson     // LCOV_EXCL_START
372b730f8bSJeremy L Thompson     return CeedError(ceed, CEED_ERROR_BACKEND, "An input vector is required for this CeedEvalMode");
38c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
39aedaa0e5Sjeremylt   }
402b730f8bSJeremy L Thompson   CeedCallBackend(CeedVectorGetArrayWrite(V, CEED_MEM_HOST, &v));
4121617c04Sjeremylt 
428d94b059Sjeremylt   // Clear v if operating in transpose
43d1d35e2fSjeremylt   if (t_mode == CEED_TRANSPOSE) {
44d1d35e2fSjeremylt     const CeedInt v_size = num_elem * num_comp * num_nodes;
452b730f8bSJeremy L Thompson     for (CeedInt i = 0; i < v_size; i++) v[i] = (CeedScalar)0.0;
4621617c04Sjeremylt   }
47d1d35e2fSjeremylt   bool tensor_basis;
482b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisIsTensor(basis, &tensor_basis));
4984a01de5SJeremy L Thompson   // Tensor basis
50d1d35e2fSjeremylt   if (tensor_basis) {
51d1d35e2fSjeremylt     CeedInt P_1d, Q_1d;
522b730f8bSJeremy L Thompson     CeedCallBackend(CeedBasisGetNumNodes1D(basis, &P_1d));
532b730f8bSJeremy L Thompson     CeedCallBackend(CeedBasisGetNumQuadraturePoints1D(basis, &Q_1d));
54d1d35e2fSjeremylt     switch (eval_mode) {
558d94b059Sjeremylt       // Interpolate to/from quadrature points
56a2b73c81Sjeremylt       case CEED_EVAL_INTERP: {
57dfe03796SJeremy L Thompson         CeedBasis_Ref *impl;
582b730f8bSJeremy L Thompson         CeedCallBackend(CeedBasisGetData(basis, &impl));
598c1105f8SJeremy L Thompson         if (impl->has_collo_interp) {
60d1d35e2fSjeremylt           memcpy(v, u, num_elem * num_comp * num_nodes * sizeof(u[0]));
61dfe03796SJeremy L Thompson         } else {
62d1d35e2fSjeremylt           CeedInt P = P_1d, Q = Q_1d;
63d1d35e2fSjeremylt           if (t_mode == CEED_TRANSPOSE) {
642b730f8bSJeremy L Thompson             P = Q_1d;
652b730f8bSJeremy L Thompson             Q = P_1d;
6621617c04Sjeremylt           }
67d1d35e2fSjeremylt           CeedInt           pre = num_comp * CeedIntPow(P, dim - 1), post = num_elem;
68d1d35e2fSjeremylt           CeedScalar        tmp[2][num_elem * num_comp * Q * CeedIntPow(P > Q ? P : Q, dim - 1)];
69d1d35e2fSjeremylt           const CeedScalar *interp_1d;
702b730f8bSJeremy L Thompson           CeedCallBackend(CeedBasisGetInterp1D(basis, &interp_1d));
7121617c04Sjeremylt           for (CeedInt d = 0; d < dim; d++) {
722b730f8bSJeremy L Thompson             CeedCallBackend(CeedTensorContractApply(contract, pre, P, post, Q, interp_1d, t_mode, add && (d == dim - 1), d == 0 ? u : tmp[d % 2],
732b730f8bSJeremy L Thompson                                                     d == dim - 1 ? v : tmp[(d + 1) % 2]));
7421617c04Sjeremylt             pre /= P;
7521617c04Sjeremylt             post *= Q;
7621617c04Sjeremylt           }
77dfe03796SJeremy L Thompson         }
78a2b73c81Sjeremylt       } break;
798d94b059Sjeremylt       // Evaluate the gradient to/from quadrature points
80a2b73c81Sjeremylt       case CEED_EVAL_GRAD: {
8121617c04Sjeremylt         // In CEED_NOTRANSPOSE mode:
82d1d35e2fSjeremylt         // u has shape [dim, num_comp, P^dim, num_elem], row-major layout
83d1d35e2fSjeremylt         // v has shape [dim, num_comp, Q^dim, num_elem], row-major layout
8421617c04Sjeremylt         // In CEED_TRANSPOSE mode, the sizes of u and v are switched.
85d1d35e2fSjeremylt         CeedInt P = P_1d, Q = Q_1d;
86d1d35e2fSjeremylt         if (t_mode == CEED_TRANSPOSE) {
87d1d35e2fSjeremylt           P = Q_1d, Q = Q_1d;
8821617c04Sjeremylt         }
8984a01de5SJeremy L Thompson         CeedBasis_Ref *impl;
902b730f8bSJeremy L Thompson         CeedCallBackend(CeedBasisGetData(basis, &impl));
91d1d35e2fSjeremylt         CeedInt           pre = num_comp * CeedIntPow(P, dim - 1), post = num_elem;
92d1d35e2fSjeremylt         const CeedScalar *interp_1d;
932b730f8bSJeremy L Thompson         CeedCallBackend(CeedBasisGetInterp1D(basis, &interp_1d));
948c1105f8SJeremy L Thompson         if (impl->collo_grad_1d) {
95d1d35e2fSjeremylt           CeedScalar tmp[2][num_elem * num_comp * Q * CeedIntPow(P > Q ? P : Q, dim - 1)];
96d1d35e2fSjeremylt           CeedScalar interp[num_elem * num_comp * Q * CeedIntPow(P > Q ? P : Q, dim - 1)];
9784a01de5SJeremy L Thompson           // Interpolate to quadrature points (NoTranspose)
9884a01de5SJeremy L Thompson           //  or Grad to quadrature points (Transpose)
9921617c04Sjeremylt           for (CeedInt d = 0; d < dim; d++) {
1002b730f8bSJeremy L Thompson             CeedCallBackend(CeedTensorContractApply(contract, pre, P, post, Q, (t_mode == CEED_NOTRANSPOSE ? interp_1d : impl->collo_grad_1d), t_mode,
1012b730f8bSJeremy L Thompson                                                     add && (d > 0),
1022b730f8bSJeremy L Thompson                                                     (t_mode == CEED_NOTRANSPOSE ? (d == 0 ? u : tmp[d % 2]) : u + d * num_qpts * num_comp * num_elem),
1032b730f8bSJeremy L Thompson                                                     (t_mode == CEED_NOTRANSPOSE ? (d == dim - 1 ? interp : tmp[(d + 1) % 2]) : interp)));
10421617c04Sjeremylt             pre /= P;
10521617c04Sjeremylt             post *= Q;
10621617c04Sjeremylt           }
10784a01de5SJeremy L Thompson           // Grad to quadrature points (NoTranspose)
1088795c945Sjeremylt           //  or Interpolate to nodes (Transpose)
109d1d35e2fSjeremylt           P = Q_1d, Q = Q_1d;
110d1d35e2fSjeremylt           if (t_mode == CEED_TRANSPOSE) {
111d1d35e2fSjeremylt             P = Q_1d, Q = P_1d;
11284a01de5SJeremy L Thompson           }
113d1d35e2fSjeremylt           pre = num_comp * CeedIntPow(P, dim - 1), post = num_elem;
11484a01de5SJeremy L Thompson           for (CeedInt d = 0; d < dim; d++) {
1152b730f8bSJeremy L Thompson             CeedCallBackend(CeedTensorContractApply(
1162b730f8bSJeremy L Thompson                 contract, pre, P, post, Q, (t_mode == CEED_NOTRANSPOSE ? impl->collo_grad_1d : interp_1d), t_mode, add && (d == dim - 1),
1172b730f8bSJeremy L Thompson                 (t_mode == CEED_NOTRANSPOSE ? interp : (d == 0 ? interp : tmp[d % 2])),
1182b730f8bSJeremy L Thompson                 (t_mode == CEED_NOTRANSPOSE ? v + d * num_qpts * num_comp * num_elem : (d == dim - 1 ? v : tmp[(d + 1) % 2]))));
11984a01de5SJeremy L Thompson             pre /= P;
12084a01de5SJeremy L Thompson             post *= Q;
12121617c04Sjeremylt           }
1228c1105f8SJeremy L Thompson         } else if (impl->has_collo_interp) {  // Qpts collocated with nodes
123d1d35e2fSjeremylt           const CeedScalar *grad_1d;
1242b730f8bSJeremy L Thompson           CeedCallBackend(CeedBasisGetGrad1D(basis, &grad_1d));
125dfe03796SJeremy L Thompson 
126dfe03796SJeremy L Thompson           // Dim contractions, identity in other directions
127d1d35e2fSjeremylt           CeedInt pre = num_comp * CeedIntPow(P, dim - 1), post = num_elem;
128c6158135Sjeremylt           for (CeedInt d = 0; d < dim; d++) {
1292b730f8bSJeremy L Thompson             CeedCallBackend(CeedTensorContractApply(contract, pre, P, post, Q, grad_1d, t_mode, add && (d > 0),
1302b730f8bSJeremy L Thompson                                                     t_mode == CEED_NOTRANSPOSE ? u : u + d * num_comp * num_qpts * num_elem,
1312b730f8bSJeremy L Thompson                                                     t_mode == CEED_TRANSPOSE ? v : v + d * num_comp * num_qpts * num_elem));
132c6158135Sjeremylt             pre /= P;
133c6158135Sjeremylt             post *= Q;
134dfe03796SJeremy L Thompson           }
135a7bd39daSjeremylt         } else {  // Underintegration, P > Q
136d1d35e2fSjeremylt           const CeedScalar *grad_1d;
1372b730f8bSJeremy L Thompson           CeedCallBackend(CeedBasisGetGrad1D(basis, &grad_1d));
138a7bd39daSjeremylt 
139d1d35e2fSjeremylt           if (t_mode == CEED_TRANSPOSE) {
140d1d35e2fSjeremylt             P = Q_1d, Q = P_1d;
141a7bd39daSjeremylt           }
142d1d35e2fSjeremylt           CeedScalar tmp[2][num_elem * num_comp * Q * CeedIntPow(P > Q ? P : Q, dim - 1)];
143a7bd39daSjeremylt 
144a7bd39daSjeremylt           // Dim**2 contractions, apply grad when pass == dim
145a7bd39daSjeremylt           for (CeedInt p = 0; p < dim; p++) {
146d1d35e2fSjeremylt             CeedInt pre = num_comp * CeedIntPow(P, dim - 1), post = num_elem;
147a7bd39daSjeremylt             for (CeedInt d = 0; d < dim; d++) {
1482b730f8bSJeremy L Thompson               CeedCallBackend(CeedTensorContractApply(
1492b730f8bSJeremy L Thompson                   contract, pre, P, post, Q, (p == d) ? grad_1d : interp_1d, t_mode, add && (d == dim - 1),
1502b730f8bSJeremy L Thompson                   (d == 0 ? (t_mode == CEED_NOTRANSPOSE ? u : u + p * num_comp * num_qpts * num_elem) : tmp[d % 2]),
1512b730f8bSJeremy L Thompson                   (d == dim - 1 ? (t_mode == CEED_TRANSPOSE ? v : v + p * num_comp * num_qpts * num_elem) : tmp[(d + 1) % 2])));
152a7bd39daSjeremylt               pre /= P;
153a7bd39daSjeremylt               post *= Q;
154a7bd39daSjeremylt             }
155a7bd39daSjeremylt           }
156a7bd39daSjeremylt         }
157a2b73c81Sjeremylt       } break;
1588d94b059Sjeremylt       // Retrieve interpolation weights
159a2b73c81Sjeremylt       case CEED_EVAL_WEIGHT: {
1602b730f8bSJeremy L Thompson         if (t_mode == CEED_TRANSPOSE) {
161c042f62fSJeremy L Thompson           // LCOV_EXCL_START
1622b730f8bSJeremy L Thompson           return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE");
163c042f62fSJeremy L Thompson           // LCOV_EXCL_STOP
1642b730f8bSJeremy L Thompson         }
165d1d35e2fSjeremylt         CeedInt           Q = Q_1d;
166d1d35e2fSjeremylt         const CeedScalar *q_weight_1d;
1672b730f8bSJeremy L Thompson         CeedCallBackend(CeedBasisGetQWeights(basis, &q_weight_1d));
16821617c04Sjeremylt         for (CeedInt d = 0; d < dim; d++) {
169b5cf12eeSjeremylt           CeedInt pre = CeedIntPow(Q, dim - d - 1), post = CeedIntPow(Q, d);
1702b730f8bSJeremy L Thompson           for (CeedInt i = 0; i < pre; i++) {
1712b730f8bSJeremy L Thompson             for (CeedInt j = 0; j < Q; j++) {
17284a01de5SJeremy L Thompson               for (CeedInt k = 0; k < post; k++) {
1732b730f8bSJeremy L Thompson                 CeedScalar w = q_weight_1d[j] * (d == 0 ? 1 : v[((i * Q + j) * post + k) * num_elem]);
1742b730f8bSJeremy L Thompson                 for (CeedInt e = 0; e < num_elem; e++) v[((i * Q + j) * post + k) * num_elem + e] = w;
1752b730f8bSJeremy L Thompson               }
1762b730f8bSJeremy L Thompson             }
17784a01de5SJeremy L Thompson           }
17821617c04Sjeremylt         }
179a2b73c81Sjeremylt       } break;
180c042f62fSJeremy L Thompson       // LCOV_EXCL_START
1818d94b059Sjeremylt       // Evaluate the divergence to/from the quadrature points
182a2b73c81Sjeremylt       case CEED_EVAL_DIV:
183e15f9bd0SJeremy L Thompson         return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_DIV not supported");
1848d94b059Sjeremylt       // Evaluate the curl to/from the quadrature points
185a2b73c81Sjeremylt       case CEED_EVAL_CURL:
186e15f9bd0SJeremy L Thompson         return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_CURL not supported");
1878d94b059Sjeremylt       // Take no action, BasisApply should not have been called
188a2b73c81Sjeremylt       case CEED_EVAL_NONE:
1892b730f8bSJeremy L Thompson         return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_NONE does not make sense in this context");
190c042f62fSJeremy L Thompson         // LCOV_EXCL_STOP
19121617c04Sjeremylt     }
192a8de75f0Sjeremylt   } else {
193a8de75f0Sjeremylt     // Non-tensor basis
194d1d35e2fSjeremylt     switch (eval_mode) {
19584a01de5SJeremy L Thompson       // Interpolate to/from quadrature points
196a8de75f0Sjeremylt       case CEED_EVAL_INTERP: {
19750c301a5SRezgar Shakeri         CeedInt           P = num_nodes, Q = Q_comp * num_qpts;
1986c58de82SJeremy L Thompson         const CeedScalar *interp;
1992b730f8bSJeremy L Thompson         CeedCallBackend(CeedBasisGetInterp(basis, &interp));
200d1d35e2fSjeremylt         if (t_mode == CEED_TRANSPOSE) {
2012b730f8bSJeremy L Thompson           P = Q_comp * num_qpts;
2022b730f8bSJeremy L Thompson           Q = num_nodes;
203a8de75f0Sjeremylt         }
2042b730f8bSJeremy L Thompson         CeedCallBackend(CeedTensorContractApply(contract, num_comp, P, num_elem, Q, interp, t_mode, add, u, v));
2052b730f8bSJeremy L Thompson       } break;
20684a01de5SJeremy L Thompson       // Evaluate the gradient to/from quadrature points
207a8de75f0Sjeremylt       case CEED_EVAL_GRAD: {
208d1d35e2fSjeremylt         CeedInt           P = num_nodes, Q = num_qpts;
209d1d35e2fSjeremylt         CeedInt           dim_stride  = num_qpts * num_comp * num_elem;
210d1d35e2fSjeremylt         CeedInt           grad_stride = num_qpts * num_nodes;
2116c58de82SJeremy L Thompson         const CeedScalar *grad;
2122b730f8bSJeremy L Thompson         CeedCallBackend(CeedBasisGetGrad(basis, &grad));
213d1d35e2fSjeremylt         if (t_mode == CEED_TRANSPOSE) {
2142b730f8bSJeremy L Thompson           P = num_qpts;
2152b730f8bSJeremy L Thompson           Q = num_nodes;
216475a782bSnbeams           for (CeedInt d = 0; d < dim; d++) {
2172b730f8bSJeremy L Thompson             CeedCallBackend(CeedTensorContractApply(contract, num_comp, P, num_elem, Q, grad + d * grad_stride, t_mode, add, u + d * dim_stride, v));
218475a782bSnbeams           }
219475a782bSnbeams         } else {
220475a782bSnbeams           for (CeedInt d = 0; d < dim; d++) {
2212b730f8bSJeremy L Thompson             CeedCallBackend(CeedTensorContractApply(contract, num_comp, P, num_elem, Q, grad + d * grad_stride, t_mode, add, u, v + d * dim_stride));
222475a782bSnbeams           }
223475a782bSnbeams         }
2242b730f8bSJeremy L Thompson       } break;
22584a01de5SJeremy L Thompson       // Retrieve interpolation weights
226a8de75f0Sjeremylt       case CEED_EVAL_WEIGHT: {
2272b730f8bSJeremy L Thompson         if (t_mode == CEED_TRANSPOSE) {
228c042f62fSJeremy L Thompson           // LCOV_EXCL_START
2292b730f8bSJeremy L Thompson           return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE");
230c042f62fSJeremy L Thompson           // LCOV_EXCL_STOP
2312b730f8bSJeremy L Thompson         }
232d1d35e2fSjeremylt         const CeedScalar *q_weight;
2332b730f8bSJeremy L Thompson         CeedCallBackend(CeedBasisGetQWeights(basis, &q_weight));
2342b730f8bSJeremy L Thompson         for (CeedInt i = 0; i < num_qpts; i++) {
2352b730f8bSJeremy L Thompson           for (CeedInt e = 0; e < num_elem; e++) v[i * num_elem + e] = q_weight[i];
2362b730f8bSJeremy L Thompson         }
237a8de75f0Sjeremylt       } break;
23884a01de5SJeremy L Thompson       // Evaluate the divergence to/from the quadrature points
23950c301a5SRezgar Shakeri       case CEED_EVAL_DIV: {
24050c301a5SRezgar Shakeri         CeedInt           P = num_nodes, Q = num_qpts;
24150c301a5SRezgar Shakeri         const CeedScalar *div;
2422b730f8bSJeremy L Thompson         CeedCallBackend(CeedBasisGetDiv(basis, &div));
24350c301a5SRezgar Shakeri         if (t_mode == CEED_TRANSPOSE) {
2442b730f8bSJeremy L Thompson           P = num_qpts;
2452b730f8bSJeremy L Thompson           Q = num_nodes;
24650c301a5SRezgar Shakeri         }
2472b730f8bSJeremy L Thompson         CeedCallBackend(CeedTensorContractApply(contract, num_comp, P, num_elem, Q, div, t_mode, add, u, v));
24850c301a5SRezgar Shakeri       } break;
24950c301a5SRezgar Shakeri       // LCOV_EXCL_START
25084a01de5SJeremy L Thompson       // Evaluate the curl to/from the quadrature points
251a8de75f0Sjeremylt       case CEED_EVAL_CURL:
252e15f9bd0SJeremy L Thompson         return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_CURL not supported");
25384a01de5SJeremy L Thompson       // Take no action, BasisApply should not have been called
254a8de75f0Sjeremylt       case CEED_EVAL_NONE:
2552b730f8bSJeremy L Thompson         return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_NONE does not make sense in this context");
256c042f62fSJeremy L Thompson         // LCOV_EXCL_STOP
257a8de75f0Sjeremylt     }
258a8de75f0Sjeremylt   }
259a7b7f929Sjeremylt   if (U != CEED_VECTOR_NONE) {
2602b730f8bSJeremy L Thompson     CeedCallBackend(CeedVectorRestoreArrayRead(U, &u));
261aedaa0e5Sjeremylt   }
2622b730f8bSJeremy L Thompson   CeedCallBackend(CeedVectorRestoreArray(V, &v));
263e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
26421617c04Sjeremylt }
26521617c04Sjeremylt 
266f10650afSjeremylt //------------------------------------------------------------------------------
26750c301a5SRezgar Shakeri // Basis Create Non-Tensor H^1
268f10650afSjeremylt //------------------------------------------------------------------------------
2692b730f8bSJeremy L Thompson int CeedBasisCreateH1_Ref(CeedElemTopology topo, CeedInt dim, CeedInt num_nodes, CeedInt num_qpts, const CeedScalar *interp, const CeedScalar *grad,
2702b730f8bSJeremy L Thompson                           const CeedScalar *q_ref, const CeedScalar *q_weight, CeedBasis basis) {
271f10650afSjeremylt   Ceed ceed;
2722b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisGetCeed(basis, &ceed));
273f10650afSjeremylt 
274f10650afSjeremylt   Ceed parent;
2752b730f8bSJeremy L Thompson   CeedCallBackend(CeedGetParent(ceed, &parent));
276f10650afSjeremylt   CeedTensorContract contract;
2772b730f8bSJeremy L Thompson   CeedCallBackend(CeedTensorContractCreate(parent, basis, &contract));
2782b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisSetTensorContract(basis, contract));
279f10650afSjeremylt 
2802b730f8bSJeremy L Thompson   CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "Apply", CeedBasisApply_Ref));
281f10650afSjeremylt 
282e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
283f10650afSjeremylt }
284f10650afSjeremylt 
285f10650afSjeremylt //------------------------------------------------------------------------------
28650c301a5SRezgar Shakeri // Basis Create Non-Tensor H(div)
28750c301a5SRezgar Shakeri //------------------------------------------------------------------------------
2882b730f8bSJeremy L Thompson int CeedBasisCreateHdiv_Ref(CeedElemTopology topo, CeedInt dim, CeedInt num_nodes, CeedInt num_qpts, const CeedScalar *interp, const CeedScalar *div,
2892b730f8bSJeremy L Thompson                             const CeedScalar *q_ref, const CeedScalar *q_weight, CeedBasis basis) {
29050c301a5SRezgar Shakeri   Ceed ceed;
2912b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisGetCeed(basis, &ceed));
29250c301a5SRezgar Shakeri 
29350c301a5SRezgar Shakeri   Ceed parent;
2942b730f8bSJeremy L Thompson   CeedCallBackend(CeedGetParent(ceed, &parent));
29550c301a5SRezgar Shakeri   CeedTensorContract contract;
2962b730f8bSJeremy L Thompson   CeedCallBackend(CeedTensorContractCreate(parent, basis, &contract));
2972b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisSetTensorContract(basis, contract));
29850c301a5SRezgar Shakeri 
2992b730f8bSJeremy L Thompson   CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "Apply", CeedBasisApply_Ref));
30050c301a5SRezgar Shakeri 
30150c301a5SRezgar Shakeri   return CEED_ERROR_SUCCESS;
30250c301a5SRezgar Shakeri }
30350c301a5SRezgar Shakeri 
30450c301a5SRezgar Shakeri //------------------------------------------------------------------------------
305f10650afSjeremylt // Basis Destroy Tensor
306f10650afSjeremylt //------------------------------------------------------------------------------
30784a01de5SJeremy L Thompson static int CeedBasisDestroyTensor_Ref(CeedBasis basis) {
30884a01de5SJeremy L Thompson   CeedBasis_Ref *impl;
3092b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisGetData(basis, &impl));
3102b730f8bSJeremy L Thompson   CeedCallBackend(CeedFree(&impl->collo_grad_1d));
3112b730f8bSJeremy L Thompson   CeedCallBackend(CeedFree(&impl));
31284a01de5SJeremy L Thompson 
313e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
31421617c04Sjeremylt }
31521617c04Sjeremylt 
316f10650afSjeremylt //------------------------------------------------------------------------------
317f10650afSjeremylt // Basis Create Tensor
318f10650afSjeremylt //------------------------------------------------------------------------------
3192b730f8bSJeremy L Thompson int CeedBasisCreateTensorH1_Ref(CeedInt dim, CeedInt P_1d, CeedInt Q_1d, const CeedScalar *interp_1d, const CeedScalar *grad_1d,
3202b730f8bSJeremy L Thompson                                 const CeedScalar *q_ref_1d, const CeedScalar *q_weight_1d, CeedBasis basis) {
321fe2413ffSjeremylt   Ceed ceed;
3222b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisGetCeed(basis, &ceed));
32384a01de5SJeremy L Thompson   CeedBasis_Ref *impl;
3242b730f8bSJeremy L Thompson   CeedCallBackend(CeedCalloc(1, &impl));
325dfe03796SJeremy L Thompson   // Check for collocated interp
326d1d35e2fSjeremylt   if (Q_1d == P_1d) {
327dfe03796SJeremy L Thompson     bool collocated = 1;
328d1d35e2fSjeremylt     for (CeedInt i = 0; i < P_1d; i++) {
329d1d35e2fSjeremylt       collocated = collocated && (fabs(interp_1d[i + P_1d * i] - 1.0) < 1e-14);
3302b730f8bSJeremy L Thompson       for (CeedInt j = 0; j < P_1d; j++) {
3312b730f8bSJeremy L Thompson         if (j != i) collocated = collocated && (fabs(interp_1d[j + P_1d * i]) < 1e-14);
3322b730f8bSJeremy L Thompson       }
333dfe03796SJeremy L Thompson     }
3348c1105f8SJeremy L Thompson     impl->has_collo_interp = collocated;
335dfe03796SJeremy L Thompson   }
336dfe03796SJeremy L Thompson   // Calculate collocated grad
3378c1105f8SJeremy L Thompson   if (Q_1d >= P_1d && !impl->has_collo_interp) {
3382b730f8bSJeremy L Thompson     CeedCallBackend(CeedMalloc(Q_1d * Q_1d, &impl->collo_grad_1d));
3392b730f8bSJeremy L Thompson     CeedCallBackend(CeedBasisGetCollocatedGrad(basis, impl->collo_grad_1d));
340a7bd39daSjeremylt   }
3412b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisSetData(basis, impl));
342fe2413ffSjeremylt 
3432f86a920SJeremy L Thompson   Ceed parent;
3442b730f8bSJeremy L Thompson   CeedCallBackend(CeedGetParent(ceed, &parent));
3452f86a920SJeremy L Thompson   CeedTensorContract contract;
3462b730f8bSJeremy L Thompson   CeedCallBackend(CeedTensorContractCreate(parent, basis, &contract));
3472b730f8bSJeremy L Thompson   CeedCallBackend(CeedBasisSetTensorContract(basis, contract));
3482f86a920SJeremy L Thompson 
3492b730f8bSJeremy L Thompson   CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "Apply", CeedBasisApply_Ref));
3502b730f8bSJeremy L Thompson   CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "Destroy", CeedBasisDestroyTensor_Ref));
351e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
35221617c04Sjeremylt }
353a8de75f0Sjeremylt 
354f10650afSjeremylt //------------------------------------------------------------------------------
355