xref: /libCEED/rust/libceed-sys/c-src/backends/ref/ceed-ref-basis.c (revision 8795c9458136fc8cad6e4d699e4c8f3c99be02e2)
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 
1721617c04Sjeremylt #include "ceed-ref.h"
1821617c04Sjeremylt 
19d3181881Sjeremylt static int CeedBasisApply_Ref(CeedBasis basis, CeedInt nelem,
20d3181881Sjeremylt                               CeedTransposeMode tmode, CeedEvalMode emode,
21aedaa0e5Sjeremylt                               CeedVector U, CeedVector V) {
2221617c04Sjeremylt   int ierr;
234ce2993fSjeremylt   Ceed ceed;
244ce2993fSjeremylt   ierr = CeedBasisGetCeed(basis, &ceed); CeedChk(ierr);
25*8795c945Sjeremylt   CeedInt dim, ncomp, nnodes, nqpt;
264ce2993fSjeremylt   ierr = CeedBasisGetDimension(basis, &dim); CeedChk(ierr);
274ce2993fSjeremylt   ierr = CeedBasisGetNumComponents(basis, &ncomp); CeedChk(ierr);
28*8795c945Sjeremylt   ierr = CeedBasisGetNumNodes(basis, &nnodes); CeedChk(ierr);
294ce2993fSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis, &nqpt); CeedChk(ierr);
302f86a920SJeremy L Thompson   CeedTensorContract contract;
312f86a920SJeremy L Thompson   ierr = CeedBasisGetTensorContract(basis, &contract); CeedChk(ierr);
3221617c04Sjeremylt   const CeedInt add = (tmode == CEED_TRANSPOSE);
33aedaa0e5Sjeremylt   const CeedScalar *u;
34aedaa0e5Sjeremylt   CeedScalar *v;
35aedaa0e5Sjeremylt   if (U) {
36aedaa0e5Sjeremylt     ierr = CeedVectorGetArrayRead(U, CEED_MEM_HOST, &u); CeedChk(ierr);
37aedaa0e5Sjeremylt   } else if (emode != CEED_EVAL_WEIGHT) {
38aedaa0e5Sjeremylt     return CeedError(ceed, 1,
39aedaa0e5Sjeremylt                      "An input vector is required for this CeedEvalMode");
40aedaa0e5Sjeremylt   }
41aedaa0e5Sjeremylt   ierr = CeedVectorGetArray(V, CEED_MEM_HOST, &v); CeedChk(ierr);
4221617c04Sjeremylt 
438d94b059Sjeremylt   // Clear v if operating in transpose
4421617c04Sjeremylt   if (tmode == CEED_TRANSPOSE) {
45*8795c945Sjeremylt     const CeedInt vsize = nelem*ncomp*nnodes;
4621617c04Sjeremylt     for (CeedInt i = 0; i < vsize; i++)
4784a01de5SJeremy L Thompson       v[i] = (CeedScalar) 0.0;
4821617c04Sjeremylt   }
494ce2993fSjeremylt   bool tensorbasis;
504ce2993fSjeremylt   ierr = CeedBasisGetTensorStatus(basis, &tensorbasis); CeedChk(ierr);
5184a01de5SJeremy L Thompson   // Tensor basis
524ce2993fSjeremylt   if (tensorbasis) {
534ce2993fSjeremylt     CeedInt P1d, Q1d;
544ce2993fSjeremylt     ierr = CeedBasisGetNumNodes1D(basis, &P1d); CeedChk(ierr);
554ce2993fSjeremylt     ierr = CeedBasisGetNumQuadraturePoints1D(basis, &Q1d); CeedChk(ierr);
56a2b73c81Sjeremylt     switch (emode) {
578d94b059Sjeremylt     // Interpolate to/from quadrature points
58a2b73c81Sjeremylt     case CEED_EVAL_INTERP: {
594ce2993fSjeremylt       CeedInt P = P1d, Q = Q1d;
6021617c04Sjeremylt       if (tmode == CEED_TRANSPOSE) {
614ce2993fSjeremylt         P = Q1d; Q = P1d;
6221617c04Sjeremylt       }
6384a01de5SJeremy L Thompson       CeedInt pre = ncomp*CeedIntPow(P, dim-1), post = nelem;
6484a01de5SJeremy L Thompson       CeedScalar tmp[2][nelem*ncomp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
654ce2993fSjeremylt       CeedScalar *interp1d;
664ce2993fSjeremylt       ierr = CeedBasisGetInterp(basis, &interp1d); CeedChk(ierr);
6721617c04Sjeremylt       for (CeedInt d=0; d<dim; d++) {
682f86a920SJeremy L Thompson         ierr = CeedTensorContractApply(contract, pre, P, post, Q,
6984a01de5SJeremy L Thompson                                        interp1d, tmode, add&&(d==dim-1),
7021617c04Sjeremylt                                        d==0?u:tmp[d%2], d==dim-1?v:tmp[(d+1)%2]);
7121617c04Sjeremylt         CeedChk(ierr);
7221617c04Sjeremylt         pre /= P;
7321617c04Sjeremylt         post *= Q;
7421617c04Sjeremylt       }
75a2b73c81Sjeremylt     } break;
768d94b059Sjeremylt     // Evaluate the gradient to/from quadrature points
77a2b73c81Sjeremylt     case CEED_EVAL_GRAD: {
7821617c04Sjeremylt       // In CEED_NOTRANSPOSE mode:
79ecf6354eSJed Brown       // u has shape [dim, ncomp, P^dim, nelem], row-major layout
80ecf6354eSJed Brown       // v has shape [dim, ncomp, Q^dim, nelem], row-major layout
8121617c04Sjeremylt       // In CEED_TRANSPOSE mode, the sizes of u and v are switched.
8284a01de5SJeremy L Thompson       CeedInt P = P1d, Q = Q1d;
8321617c04Sjeremylt       if (tmode == CEED_TRANSPOSE) {
8484a01de5SJeremy L Thompson         P = Q1d, Q = Q1d;
8521617c04Sjeremylt       }
8684a01de5SJeremy L Thompson       CeedBasis_Ref *impl;
8784a01de5SJeremy L Thompson       ierr = CeedBasisGetData(basis, (void *)&impl); CeedChk(ierr);
8884a01de5SJeremy L Thompson       CeedInt pre = ncomp*CeedIntPow(P, dim-1), post = nelem;
8984a01de5SJeremy L Thompson       CeedScalar *interp1d;
904ce2993fSjeremylt       ierr = CeedBasisGetInterp(basis, &interp1d); CeedChk(ierr);
91a7bd39daSjeremylt       if (impl->colograd1d) {
92a7bd39daSjeremylt         CeedScalar tmp[2][nelem*ncomp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
93a7bd39daSjeremylt         CeedScalar interp[nelem*ncomp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
9484a01de5SJeremy L Thompson         // Interpolate to quadrature points (NoTranspose)
9584a01de5SJeremy L Thompson         //  or Grad to quadrature points (Transpose)
9621617c04Sjeremylt         for (CeedInt d=0; d<dim; d++) {
972f86a920SJeremy L Thompson           ierr = CeedTensorContractApply(contract, pre, P, post, Q,
9884a01de5SJeremy L Thompson                                          (tmode == CEED_NOTRANSPOSE
9984a01de5SJeremy L Thompson                                           ? interp1d
10084a01de5SJeremy L Thompson                                           : impl->colograd1d),
10184a01de5SJeremy L Thompson                                          tmode, add&&(d>0),
10284a01de5SJeremy L Thompson                                          (tmode == CEED_NOTRANSPOSE
10384a01de5SJeremy L Thompson                                           ? (d==0?u:tmp[d%2])
10484a01de5SJeremy L Thompson                                           : u + d*nqpt*ncomp*nelem),
10584a01de5SJeremy L Thompson                                          (tmode == CEED_NOTRANSPOSE
10684a01de5SJeremy L Thompson                                           ? (d==dim-1?interp:tmp[(d+1)%2])
10784a01de5SJeremy L Thompson                                           : interp));
10821617c04Sjeremylt           CeedChk(ierr);
10921617c04Sjeremylt           pre /= P;
11021617c04Sjeremylt           post *= Q;
11121617c04Sjeremylt         }
11284a01de5SJeremy L Thompson         // Grad to quadrature points (NoTranspose)
113*8795c945Sjeremylt         //  or Interpolate to nodes (Transpose)
11484a01de5SJeremy L Thompson         P = Q1d, Q = Q1d;
11584a01de5SJeremy L Thompson         if (tmode == CEED_TRANSPOSE) {
11684a01de5SJeremy L Thompson           P = Q1d, Q = P1d;
11784a01de5SJeremy L Thompson         }
11884a01de5SJeremy L Thompson         pre = ncomp*CeedIntPow(P, dim-1), post = nelem;
11984a01de5SJeremy L Thompson         for (CeedInt d=0; d<dim; d++) {
1202f86a920SJeremy L Thompson           ierr = CeedTensorContractApply(contract, pre, P, post, Q,
12184a01de5SJeremy L Thompson                                          (tmode == CEED_NOTRANSPOSE
12284a01de5SJeremy L Thompson                                           ? impl->colograd1d
12384a01de5SJeremy L Thompson                                           : interp1d),
12484a01de5SJeremy L Thompson                                          tmode, add&&(d==dim-1),
12584a01de5SJeremy L Thompson                                          (tmode == CEED_NOTRANSPOSE
12684a01de5SJeremy L Thompson                                           ? interp
12784a01de5SJeremy L Thompson                                           : (d==0?interp:tmp[d%2])),
12884a01de5SJeremy L Thompson                                          (tmode == CEED_NOTRANSPOSE
12984a01de5SJeremy L Thompson                                           ? v + d*nqpt*ncomp*nelem
13084a01de5SJeremy L Thompson                                           : (d==dim-1?v:tmp[(d+1)%2])));
13184a01de5SJeremy L Thompson           CeedChk(ierr);
13284a01de5SJeremy L Thompson           pre /= P;
13384a01de5SJeremy L Thompson           post *= Q;
13421617c04Sjeremylt         }
135a7bd39daSjeremylt       } else { // Underintegration, P > Q
136a7bd39daSjeremylt         CeedScalar *grad1d;
137a7bd39daSjeremylt         ierr = CeedBasisGetGrad(basis, &grad1d); CeedChk(ierr);
138a7bd39daSjeremylt 
139a7bd39daSjeremylt         if (tmode == CEED_TRANSPOSE) {
140a7bd39daSjeremylt           P = Q1d, Q = P1d;
141a7bd39daSjeremylt         }
142a7bd39daSjeremylt         CeedScalar tmp[2][nelem*ncomp*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++) {
146a7bd39daSjeremylt           CeedInt pre = ncomp*CeedIntPow(P, dim-1), post = nelem;
147a7bd39daSjeremylt           for (CeedInt d=0; d<dim; d++) {
148a7bd39daSjeremylt             ierr = CeedTensorContractApply(contract, pre, P, post, Q,
149a7bd39daSjeremylt                                            (p==d)? grad1d : interp1d,
150a7bd39daSjeremylt                                            tmode, add&&(d==dim-1),
151a7bd39daSjeremylt                                            (d == 0
152a7bd39daSjeremylt                                             ? (tmode == CEED_NOTRANSPOSE
153a7bd39daSjeremylt                                                ? u : u+p*ncomp*nqpt*nelem)
154a7bd39daSjeremylt                                             : tmp[d%2]),
155a7bd39daSjeremylt                                            (d == dim-1
156a7bd39daSjeremylt                                             ? (tmode == CEED_TRANSPOSE
157a7bd39daSjeremylt                                                ? v : v+p*ncomp*nqpt*nelem)
158a7bd39daSjeremylt                                             : tmp[(d+1)%2]));
159a7bd39daSjeremylt             CeedChk(ierr);
160a7bd39daSjeremylt             pre /= P;
161a7bd39daSjeremylt             post *= Q;
162a7bd39daSjeremylt           }
163a7bd39daSjeremylt         }
164a7bd39daSjeremylt       }
165a2b73c81Sjeremylt     } break;
1668d94b059Sjeremylt     // Retrieve interpolation weights
167a2b73c81Sjeremylt     case CEED_EVAL_WEIGHT: {
16821617c04Sjeremylt       if (tmode == CEED_TRANSPOSE)
1694ce2993fSjeremylt         return CeedError(ceed, 1,
17021617c04Sjeremylt                          "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE");
1714ce2993fSjeremylt       CeedInt Q = Q1d;
1724ce2993fSjeremylt       CeedScalar *qweight1d;
1734ce2993fSjeremylt       ierr = CeedBasisGetQWeights(basis, &qweight1d); CeedChk(ierr);
17421617c04Sjeremylt       for (CeedInt d=0; d<dim; d++) {
175b5cf12eeSjeremylt         CeedInt pre = CeedIntPow(Q, dim-d-1), post = CeedIntPow(Q, d);
176a2b73c81Sjeremylt         for (CeedInt i=0; i<pre; i++)
177a2b73c81Sjeremylt           for (CeedInt j=0; j<Q; j++)
17884a01de5SJeremy L Thompson             for (CeedInt k=0; k<post; k++) {
17984a01de5SJeremy L Thompson               CeedScalar w = qweight1d[j]
18084a01de5SJeremy L Thompson                              * (d == 0 ? 1 : v[((i*Q + j)*post + k)*nelem]);
18184a01de5SJeremy L Thompson               for (CeedInt e=0; e<nelem; e++)
18284a01de5SJeremy L Thompson                 v[((i*Q + j)*post + k)*nelem + e] = w;
18384a01de5SJeremy L Thompson             }
18421617c04Sjeremylt       }
185a2b73c81Sjeremylt     } break;
1868d94b059Sjeremylt     // Evaluate the divergence to/from the quadrature points
187a2b73c81Sjeremylt     case CEED_EVAL_DIV:
1884ce2993fSjeremylt       return CeedError(ceed, 1, "CEED_EVAL_DIV not supported");
1898d94b059Sjeremylt     // Evaluate the curl to/from the quadrature points
190a2b73c81Sjeremylt     case CEED_EVAL_CURL:
1914ce2993fSjeremylt       return CeedError(ceed, 1, "CEED_EVAL_CURL not supported");
1928d94b059Sjeremylt     // Take no action, BasisApply should not have been called
193a2b73c81Sjeremylt     case CEED_EVAL_NONE:
1944ce2993fSjeremylt       return CeedError(ceed, 1,
1954b8bea3bSJed Brown                        "CEED_EVAL_NONE does not make sense in this context");
19621617c04Sjeremylt     }
197a8de75f0Sjeremylt   } else {
198a8de75f0Sjeremylt     // Non-tensor basis
199a8de75f0Sjeremylt     switch (emode) {
20084a01de5SJeremy L Thompson     // Interpolate to/from quadrature points
201a8de75f0Sjeremylt     case CEED_EVAL_INTERP: {
202*8795c945Sjeremylt       CeedInt P = nnodes, Q = nqpt;
2034ce2993fSjeremylt       CeedScalar *interp;
2044ce2993fSjeremylt       ierr = CeedBasisGetInterp(basis, &interp); CeedChk(ierr);
205a8de75f0Sjeremylt       if (tmode == CEED_TRANSPOSE) {
206*8795c945Sjeremylt         P = nqpt; Q = nnodes;
207a8de75f0Sjeremylt       }
2082f86a920SJeremy L Thompson       ierr = CeedTensorContractApply(contract, ncomp, P, nelem, Q,
20984a01de5SJeremy L Thompson                                      interp, tmode, add, u, v);
210a8de75f0Sjeremylt       CeedChk(ierr);
211a8de75f0Sjeremylt     }
212a8de75f0Sjeremylt     break;
21384a01de5SJeremy L Thompson     // Evaluate the gradient to/from quadrature points
214a8de75f0Sjeremylt     case CEED_EVAL_GRAD: {
215*8795c945Sjeremylt       CeedInt P = nnodes, Q = dim*nqpt;
2164ce2993fSjeremylt       CeedScalar *grad;
2174ce2993fSjeremylt       ierr = CeedBasisGetGrad(basis, &grad); CeedChk(ierr);
218a8de75f0Sjeremylt       if (tmode == CEED_TRANSPOSE) {
219*8795c945Sjeremylt         P = dim*nqpt; Q = nnodes;
220a8de75f0Sjeremylt       }
2212f86a920SJeremy L Thompson       ierr = CeedTensorContractApply(contract, ncomp, P, nelem, Q,
22284a01de5SJeremy L Thompson                                      grad, tmode, add, u, v);
223a8de75f0Sjeremylt       CeedChk(ierr);
224a8de75f0Sjeremylt     }
225a8de75f0Sjeremylt     break;
22684a01de5SJeremy L Thompson     // Retrieve interpolation weights
227a8de75f0Sjeremylt     case CEED_EVAL_WEIGHT: {
228a8de75f0Sjeremylt       if (tmode == CEED_TRANSPOSE)
2294ce2993fSjeremylt         return CeedError(ceed, 1,
230a8de75f0Sjeremylt                          "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE");
2314ce2993fSjeremylt       CeedScalar *qweight;
2324ce2993fSjeremylt       ierr = CeedBasisGetQWeights(basis, &qweight); CeedChk(ierr);
233a8de75f0Sjeremylt       for (CeedInt i=0; i<nqpt; i++)
23484a01de5SJeremy L Thompson         for (CeedInt e=0; e<nelem; e++)
23584a01de5SJeremy L Thompson           v[i*nelem + e] = qweight[i];
236a8de75f0Sjeremylt     } break;
23784a01de5SJeremy L Thompson     // Evaluate the divergence to/from the quadrature points
238a8de75f0Sjeremylt     case CEED_EVAL_DIV:
2394ce2993fSjeremylt       return CeedError(ceed, 1, "CEED_EVAL_DIV not supported");
24084a01de5SJeremy L Thompson     // Evaluate the curl to/from the quadrature points
241a8de75f0Sjeremylt     case CEED_EVAL_CURL:
2424ce2993fSjeremylt       return CeedError(ceed, 1, "CEED_EVAL_CURL not supported");
24384a01de5SJeremy L Thompson     // Take no action, BasisApply should not have been called
244a8de75f0Sjeremylt     case CEED_EVAL_NONE:
2454ce2993fSjeremylt       return CeedError(ceed, 1,
246a8de75f0Sjeremylt                        "CEED_EVAL_NONE does not make sense in this context");
247a8de75f0Sjeremylt     }
248a8de75f0Sjeremylt   }
249aedaa0e5Sjeremylt   if (U) {
250aedaa0e5Sjeremylt     ierr = CeedVectorRestoreArrayRead(U, &u); CeedChk(ierr);
251aedaa0e5Sjeremylt   }
252aedaa0e5Sjeremylt   ierr = CeedVectorRestoreArray(V, &v); CeedChk(ierr);
25321617c04Sjeremylt   return 0;
25421617c04Sjeremylt }
25521617c04Sjeremylt 
25684a01de5SJeremy L Thompson static int CeedBasisDestroyNonTensor_Ref(CeedBasis basis) {
2572f86a920SJeremy L Thompson   int ierr;
2582f86a920SJeremy L Thompson   CeedTensorContract contract;
2592f86a920SJeremy L Thompson   ierr = CeedBasisGetTensorContract(basis, &contract); CeedChk(ierr);
2602f86a920SJeremy L Thompson   ierr = CeedTensorContractDestroy(&contract); CeedChk(ierr);
26184a01de5SJeremy L Thompson   return 0;
26284a01de5SJeremy L Thompson }
26384a01de5SJeremy L Thompson 
26484a01de5SJeremy L Thompson static int CeedBasisDestroyTensor_Ref(CeedBasis basis) {
26584a01de5SJeremy L Thompson   int ierr;
2662f86a920SJeremy L Thompson   CeedTensorContract contract;
2672f86a920SJeremy L Thompson   ierr = CeedBasisGetTensorContract(basis, &contract); CeedChk(ierr);
2682f86a920SJeremy L Thompson   ierr = CeedTensorContractDestroy(&contract); CeedChk(ierr);
2692f86a920SJeremy L Thompson 
27084a01de5SJeremy L Thompson   CeedBasis_Ref *impl;
27184a01de5SJeremy L Thompson   ierr = CeedBasisGetData(basis, (void *)&impl); CeedChk(ierr);
27284a01de5SJeremy L Thompson   ierr = CeedFree(&impl->colograd1d); CeedChk(ierr);
27384a01de5SJeremy L Thompson   ierr = CeedFree(&impl); CeedChk(ierr);
27484a01de5SJeremy L Thompson 
27521617c04Sjeremylt   return 0;
27621617c04Sjeremylt }
27721617c04Sjeremylt 
278667bc5fcSjeremylt int CeedBasisCreateTensorH1_Ref(CeedInt dim, CeedInt P1d,
27921617c04Sjeremylt                                 CeedInt Q1d, const CeedScalar *interp1d,
28021617c04Sjeremylt                                 const CeedScalar *grad1d,
28121617c04Sjeremylt                                 const CeedScalar *qref1d,
28221617c04Sjeremylt                                 const CeedScalar *qweight1d,
28321617c04Sjeremylt                                 CeedBasis basis) {
284fe2413ffSjeremylt   int ierr;
285fe2413ffSjeremylt   Ceed ceed;
286fe2413ffSjeremylt   ierr = CeedBasisGetCeed(basis, &ceed); CeedChk(ierr);
28784a01de5SJeremy L Thompson   CeedBasis_Ref *impl;
28884a01de5SJeremy L Thompson   ierr = CeedCalloc(1, &impl); CeedChk(ierr);
289a7bd39daSjeremylt   if (Q1d >= P1d) {
29084a01de5SJeremy L Thompson     ierr = CeedMalloc(Q1d*Q1d, &impl->colograd1d); CeedChk(ierr);
29184a01de5SJeremy L Thompson     ierr = CeedBasisGetCollocatedGrad(basis, impl->colograd1d); CeedChk(ierr);
292a7bd39daSjeremylt   }
29384a01de5SJeremy L Thompson   ierr = CeedBasisSetData(basis, (void *)&impl); CeedChk(ierr);
294fe2413ffSjeremylt 
2952f86a920SJeremy L Thompson   Ceed parent;
296de686571SJeremy L Thompson   ierr = CeedGetParent(ceed, &parent); CeedChk(ierr);
2972f86a920SJeremy L Thompson   CeedTensorContract contract;
298c71e1dcdSjeremylt   ierr = CeedTensorContractCreate(parent, basis, &contract); CeedChk(ierr);
2992f86a920SJeremy L Thompson   ierr = CeedBasisSetTensorContract(basis, &contract); CeedChk(ierr);
3002f86a920SJeremy L Thompson 
301fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Apply",
302fe2413ffSjeremylt                                 CeedBasisApply_Ref); CeedChk(ierr);
303fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Destroy",
30484a01de5SJeremy L Thompson                                 CeedBasisDestroyTensor_Ref); CeedChk(ierr);
30521617c04Sjeremylt   return 0;
30621617c04Sjeremylt }
307a8de75f0Sjeremylt 
30884a01de5SJeremy L Thompson 
30984a01de5SJeremy L Thompson 
310667bc5fcSjeremylt int CeedBasisCreateH1_Ref(CeedElemTopology topo, CeedInt dim,
311*8795c945Sjeremylt                           CeedInt nnodes, CeedInt nqpts,
312a8de75f0Sjeremylt                           const CeedScalar *interp,
313a8de75f0Sjeremylt                           const CeedScalar *grad,
314a8de75f0Sjeremylt                           const CeedScalar *qref,
315a8de75f0Sjeremylt                           const CeedScalar *qweight,
316a8de75f0Sjeremylt                           CeedBasis basis) {
317fe2413ffSjeremylt   int ierr;
318fe2413ffSjeremylt   Ceed ceed;
319fe2413ffSjeremylt   ierr = CeedBasisGetCeed(basis, &ceed); CeedChk(ierr);
320fe2413ffSjeremylt 
321c71e1dcdSjeremylt   Ceed parent;
322c71e1dcdSjeremylt   ierr = CeedGetParent(ceed, &parent); CeedChk(ierr);
3232f86a920SJeremy L Thompson   CeedTensorContract contract;
324c71e1dcdSjeremylt   ierr = CeedTensorContractCreate(parent, basis, &contract); CeedChk(ierr);
3252f86a920SJeremy L Thompson   ierr = CeedBasisSetTensorContract(basis, &contract); CeedChk(ierr);
3262f86a920SJeremy L Thompson 
327fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Apply",
328fe2413ffSjeremylt                                 CeedBasisApply_Ref); CeedChk(ierr);
329fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Destroy",
33084a01de5SJeremy L Thompson                                 CeedBasisDestroyNonTensor_Ref); CeedChk(ierr);
33184a01de5SJeremy L Thompson 
332a8de75f0Sjeremylt   return 0;
333a8de75f0Sjeremylt }
334