xref: /libCEED/rust/libceed-sys/c-src/backends/ref/ceed-ref-basis.c (revision 475a782b347f9337f5b4b708d1cb11cf41f2fc46)
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);
258795c945Sjeremylt   CeedInt dim, ncomp, nnodes, nqpt;
264ce2993fSjeremylt   ierr = CeedBasisGetDimension(basis, &dim); CeedChk(ierr);
274ce2993fSjeremylt   ierr = CeedBasisGetNumComponents(basis, &ncomp); CeedChk(ierr);
288795c945Sjeremylt   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) {
38c042f62fSJeremy L Thompson     // LCOV_EXCL_START
39aedaa0e5Sjeremylt     return CeedError(ceed, 1,
40aedaa0e5Sjeremylt                      "An input vector is required for this CeedEvalMode");
41c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
42aedaa0e5Sjeremylt   }
43aedaa0e5Sjeremylt   ierr = CeedVectorGetArray(V, CEED_MEM_HOST, &v); CeedChk(ierr);
4421617c04Sjeremylt 
458d94b059Sjeremylt   // Clear v if operating in transpose
4621617c04Sjeremylt   if (tmode == CEED_TRANSPOSE) {
478795c945Sjeremylt     const CeedInt vsize = nelem*ncomp*nnodes;
4821617c04Sjeremylt     for (CeedInt i = 0; i < vsize; i++)
4984a01de5SJeremy L Thompson       v[i] = (CeedScalar) 0.0;
5021617c04Sjeremylt   }
514ce2993fSjeremylt   bool tensorbasis;
524ce2993fSjeremylt   ierr = CeedBasisGetTensorStatus(basis, &tensorbasis); CeedChk(ierr);
5384a01de5SJeremy L Thompson   // Tensor basis
544ce2993fSjeremylt   if (tensorbasis) {
554ce2993fSjeremylt     CeedInt P1d, Q1d;
564ce2993fSjeremylt     ierr = CeedBasisGetNumNodes1D(basis, &P1d); CeedChk(ierr);
574ce2993fSjeremylt     ierr = CeedBasisGetNumQuadraturePoints1D(basis, &Q1d); CeedChk(ierr);
58a2b73c81Sjeremylt     switch (emode) {
598d94b059Sjeremylt     // Interpolate to/from quadrature points
60a2b73c81Sjeremylt     case CEED_EVAL_INTERP: {
61dfe03796SJeremy L Thompson       CeedBasis_Ref *impl;
62dfe03796SJeremy L Thompson       ierr = CeedBasisGetData(basis, (void *)&impl); CeedChk(ierr);
63dfe03796SJeremy L Thompson       if (impl->collointerp) {
64dfe03796SJeremy L Thompson         memcpy(v, u, nelem*ncomp*nnodes*sizeof(u[0]));
65dfe03796SJeremy L Thompson       } else {
664ce2993fSjeremylt         CeedInt P = P1d, Q = Q1d;
6721617c04Sjeremylt         if (tmode == CEED_TRANSPOSE) {
684ce2993fSjeremylt           P = Q1d; Q = P1d;
6921617c04Sjeremylt         }
7084a01de5SJeremy L Thompson         CeedInt pre = ncomp*CeedIntPow(P, dim-1), post = nelem;
7184a01de5SJeremy L Thompson         CeedScalar tmp[2][nelem*ncomp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
724ce2993fSjeremylt         CeedScalar *interp1d;
734ce2993fSjeremylt         ierr = CeedBasisGetInterp(basis, &interp1d); CeedChk(ierr);
7421617c04Sjeremylt         for (CeedInt d=0; d<dim; d++) {
752f86a920SJeremy L Thompson           ierr = CeedTensorContractApply(contract, pre, P, post, Q,
7684a01de5SJeremy L Thompson                                          interp1d, tmode, add&&(d==dim-1),
77dfe03796SJeremy L Thompson                                          d==0?u:tmp[d%2],
78dfe03796SJeremy L Thompson                                          d==dim-1?v:tmp[(d+1)%2]);
7921617c04Sjeremylt           CeedChk(ierr);
8021617c04Sjeremylt           pre /= P;
8121617c04Sjeremylt           post *= Q;
8221617c04Sjeremylt         }
83dfe03796SJeremy L Thompson       }
84a2b73c81Sjeremylt     } break;
858d94b059Sjeremylt     // Evaluate the gradient to/from quadrature points
86a2b73c81Sjeremylt     case CEED_EVAL_GRAD: {
8721617c04Sjeremylt       // In CEED_NOTRANSPOSE mode:
88ecf6354eSJed Brown       // u has shape [dim, ncomp, P^dim, nelem], row-major layout
89ecf6354eSJed Brown       // v has shape [dim, ncomp, Q^dim, nelem], row-major layout
9021617c04Sjeremylt       // In CEED_TRANSPOSE mode, the sizes of u and v are switched.
9184a01de5SJeremy L Thompson       CeedInt P = P1d, Q = Q1d;
9221617c04Sjeremylt       if (tmode == CEED_TRANSPOSE) {
9384a01de5SJeremy L Thompson         P = Q1d, Q = Q1d;
9421617c04Sjeremylt       }
9584a01de5SJeremy L Thompson       CeedBasis_Ref *impl;
9684a01de5SJeremy L Thompson       ierr = CeedBasisGetData(basis, (void *)&impl); CeedChk(ierr);
9784a01de5SJeremy L Thompson       CeedInt pre = ncomp*CeedIntPow(P, dim-1), post = nelem;
9884a01de5SJeremy L Thompson       CeedScalar *interp1d;
994ce2993fSjeremylt       ierr = CeedBasisGetInterp(basis, &interp1d); CeedChk(ierr);
100dfe03796SJeremy L Thompson       if (impl->collograd1d) {
101a7bd39daSjeremylt         CeedScalar tmp[2][nelem*ncomp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
102a7bd39daSjeremylt         CeedScalar interp[nelem*ncomp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
10384a01de5SJeremy L Thompson         // Interpolate to quadrature points (NoTranspose)
10484a01de5SJeremy L Thompson         //  or Grad to quadrature points (Transpose)
10521617c04Sjeremylt         for (CeedInt d=0; d<dim; d++) {
1062f86a920SJeremy L Thompson           ierr = CeedTensorContractApply(contract, pre, P, post, Q,
10784a01de5SJeremy L Thompson                                          (tmode == CEED_NOTRANSPOSE
10884a01de5SJeremy L Thompson                                           ? interp1d
109dfe03796SJeremy L Thompson                                           : impl->collograd1d),
11084a01de5SJeremy L Thompson                                          tmode, add&&(d>0),
11184a01de5SJeremy L Thompson                                          (tmode == CEED_NOTRANSPOSE
11284a01de5SJeremy L Thompson                                           ? (d==0?u:tmp[d%2])
11384a01de5SJeremy L Thompson                                           : u + d*nqpt*ncomp*nelem),
11484a01de5SJeremy L Thompson                                          (tmode == CEED_NOTRANSPOSE
11584a01de5SJeremy L Thompson                                           ? (d==dim-1?interp:tmp[(d+1)%2])
11684a01de5SJeremy L Thompson                                           : interp));
11721617c04Sjeremylt           CeedChk(ierr);
11821617c04Sjeremylt           pre /= P;
11921617c04Sjeremylt           post *= Q;
12021617c04Sjeremylt         }
12184a01de5SJeremy L Thompson         // Grad to quadrature points (NoTranspose)
1228795c945Sjeremylt         //  or Interpolate to nodes (Transpose)
12384a01de5SJeremy L Thompson         P = Q1d, Q = Q1d;
12484a01de5SJeremy L Thompson         if (tmode == CEED_TRANSPOSE) {
12584a01de5SJeremy L Thompson           P = Q1d, Q = P1d;
12684a01de5SJeremy L Thompson         }
12784a01de5SJeremy L Thompson         pre = ncomp*CeedIntPow(P, dim-1), post = nelem;
12884a01de5SJeremy L Thompson         for (CeedInt d=0; d<dim; d++) {
1292f86a920SJeremy L Thompson           ierr = CeedTensorContractApply(contract, pre, P, post, Q,
13084a01de5SJeremy L Thompson                                          (tmode == CEED_NOTRANSPOSE
131dfe03796SJeremy L Thompson                                           ? impl->collograd1d
13284a01de5SJeremy L Thompson                                           : interp1d),
13384a01de5SJeremy L Thompson                                          tmode, add&&(d==dim-1),
13484a01de5SJeremy L Thompson                                          (tmode == CEED_NOTRANSPOSE
13584a01de5SJeremy L Thompson                                           ? interp
13684a01de5SJeremy L Thompson                                           : (d==0?interp:tmp[d%2])),
13784a01de5SJeremy L Thompson                                          (tmode == CEED_NOTRANSPOSE
13884a01de5SJeremy L Thompson                                           ? v + d*nqpt*ncomp*nelem
13984a01de5SJeremy L Thompson                                           : (d==dim-1?v:tmp[(d+1)%2])));
14084a01de5SJeremy L Thompson           CeedChk(ierr);
14184a01de5SJeremy L Thompson           pre /= P;
14284a01de5SJeremy L Thompson           post *= Q;
14321617c04Sjeremylt         }
144dfe03796SJeremy L Thompson       } else if (impl->collointerp) { // Qpts collocated with nodes
145dfe03796SJeremy L Thompson         CeedScalar *grad1d;
146dfe03796SJeremy L Thompson         ierr = CeedBasisGetGrad(basis, &grad1d); CeedChk(ierr);
147dfe03796SJeremy L Thompson 
148dfe03796SJeremy L Thompson         // Dim contractions, identity in other directions
149dfe03796SJeremy L Thompson         for (CeedInt d=0; d<dim; d++) {
150dfe03796SJeremy L Thompson           CeedInt pre = ncomp*CeedIntPow(P, dim-1), post = nelem;
151dfe03796SJeremy L Thompson           ierr = CeedTensorContractApply(contract, pre, P, post, Q,
152a1dbd226Sjeremylt                                          grad1d, tmode, add&&(d>0),
153dfe03796SJeremy L Thompson                                          tmode == CEED_NOTRANSPOSE
154dfe03796SJeremy L Thompson                                          ? u : u+d*ncomp*nqpt*nelem,
155dfe03796SJeremy L Thompson                                          tmode == CEED_TRANSPOSE
156dfe03796SJeremy L Thompson                                          ? v : v+d*ncomp*nqpt*nelem);
157dfe03796SJeremy L Thompson           CeedChk(ierr);
158dfe03796SJeremy L Thompson         }
159a7bd39daSjeremylt       } else { // Underintegration, P > Q
160a7bd39daSjeremylt         CeedScalar *grad1d;
161a7bd39daSjeremylt         ierr = CeedBasisGetGrad(basis, &grad1d); CeedChk(ierr);
162a7bd39daSjeremylt 
163a7bd39daSjeremylt         if (tmode == CEED_TRANSPOSE) {
164a7bd39daSjeremylt           P = Q1d, Q = P1d;
165a7bd39daSjeremylt         }
166a7bd39daSjeremylt         CeedScalar tmp[2][nelem*ncomp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
167a7bd39daSjeremylt 
168a7bd39daSjeremylt         // Dim**2 contractions, apply grad when pass == dim
169a7bd39daSjeremylt         for (CeedInt p=0; p<dim; p++) {
170a7bd39daSjeremylt           CeedInt pre = ncomp*CeedIntPow(P, dim-1), post = nelem;
171a7bd39daSjeremylt           for (CeedInt d=0; d<dim; d++) {
172a7bd39daSjeremylt             ierr = CeedTensorContractApply(contract, pre, P, post, Q,
173a7bd39daSjeremylt                                            (p==d)? grad1d : interp1d,
174a7bd39daSjeremylt                                            tmode, add&&(d==dim-1),
175a7bd39daSjeremylt                                            (d == 0
176a7bd39daSjeremylt                                             ? (tmode == CEED_NOTRANSPOSE
177a7bd39daSjeremylt                                                ? u : u+p*ncomp*nqpt*nelem)
178a7bd39daSjeremylt                                             : tmp[d%2]),
179a7bd39daSjeremylt                                            (d == dim-1
180a7bd39daSjeremylt                                             ? (tmode == CEED_TRANSPOSE
181a7bd39daSjeremylt                                                ? v : v+p*ncomp*nqpt*nelem)
182a7bd39daSjeremylt                                             : tmp[(d+1)%2]));
183a7bd39daSjeremylt             CeedChk(ierr);
184a7bd39daSjeremylt             pre /= P;
185a7bd39daSjeremylt             post *= Q;
186a7bd39daSjeremylt           }
187a7bd39daSjeremylt         }
188a7bd39daSjeremylt       }
189a2b73c81Sjeremylt     } break;
1908d94b059Sjeremylt     // Retrieve interpolation weights
191a2b73c81Sjeremylt     case CEED_EVAL_WEIGHT: {
19221617c04Sjeremylt       if (tmode == CEED_TRANSPOSE)
193c042f62fSJeremy L Thompson         // LCOV_EXCL_START
1944ce2993fSjeremylt         return CeedError(ceed, 1,
19521617c04Sjeremylt                          "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE");
196c042f62fSJeremy L Thompson       // LCOV_EXCL_STOP
1974ce2993fSjeremylt       CeedInt Q = Q1d;
1984ce2993fSjeremylt       CeedScalar *qweight1d;
1994ce2993fSjeremylt       ierr = CeedBasisGetQWeights(basis, &qweight1d); CeedChk(ierr);
20021617c04Sjeremylt       for (CeedInt d=0; d<dim; d++) {
201b5cf12eeSjeremylt         CeedInt pre = CeedIntPow(Q, dim-d-1), post = CeedIntPow(Q, d);
202a2b73c81Sjeremylt         for (CeedInt i=0; i<pre; i++)
203a2b73c81Sjeremylt           for (CeedInt j=0; j<Q; j++)
20484a01de5SJeremy L Thompson             for (CeedInt k=0; k<post; k++) {
20584a01de5SJeremy L Thompson               CeedScalar w = qweight1d[j]
20684a01de5SJeremy L Thompson                              * (d == 0 ? 1 : v[((i*Q + j)*post + k)*nelem]);
20784a01de5SJeremy L Thompson               for (CeedInt e=0; e<nelem; e++)
20884a01de5SJeremy L Thompson                 v[((i*Q + j)*post + k)*nelem + e] = w;
20984a01de5SJeremy L Thompson             }
21021617c04Sjeremylt       }
211a2b73c81Sjeremylt     } break;
212c042f62fSJeremy L Thompson     // LCOV_EXCL_START
2138d94b059Sjeremylt     // Evaluate the divergence to/from the quadrature points
214a2b73c81Sjeremylt     case CEED_EVAL_DIV:
2154ce2993fSjeremylt       return CeedError(ceed, 1, "CEED_EVAL_DIV not supported");
2168d94b059Sjeremylt     // Evaluate the curl to/from the quadrature points
217a2b73c81Sjeremylt     case CEED_EVAL_CURL:
2184ce2993fSjeremylt       return CeedError(ceed, 1, "CEED_EVAL_CURL not supported");
2198d94b059Sjeremylt     // Take no action, BasisApply should not have been called
220a2b73c81Sjeremylt     case CEED_EVAL_NONE:
2214ce2993fSjeremylt       return CeedError(ceed, 1,
2224b8bea3bSJed Brown                        "CEED_EVAL_NONE does not make sense in this context");
223c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
22421617c04Sjeremylt     }
225a8de75f0Sjeremylt   } else {
226a8de75f0Sjeremylt     // Non-tensor basis
227a8de75f0Sjeremylt     switch (emode) {
22884a01de5SJeremy L Thompson     // Interpolate to/from quadrature points
229a8de75f0Sjeremylt     case CEED_EVAL_INTERP: {
2308795c945Sjeremylt       CeedInt P = nnodes, Q = nqpt;
2314ce2993fSjeremylt       CeedScalar *interp;
2324ce2993fSjeremylt       ierr = CeedBasisGetInterp(basis, &interp); CeedChk(ierr);
233a8de75f0Sjeremylt       if (tmode == CEED_TRANSPOSE) {
2348795c945Sjeremylt         P = nqpt; Q = nnodes;
235a8de75f0Sjeremylt       }
2362f86a920SJeremy L Thompson       ierr = CeedTensorContractApply(contract, ncomp, P, nelem, Q,
23784a01de5SJeremy L Thompson                                      interp, tmode, add, u, v);
238a8de75f0Sjeremylt       CeedChk(ierr);
239a8de75f0Sjeremylt     }
240a8de75f0Sjeremylt     break;
24184a01de5SJeremy L Thompson     // Evaluate the gradient to/from quadrature points
242a8de75f0Sjeremylt     case CEED_EVAL_GRAD: {
243*475a782bSnbeams       CeedInt P = nnodes, Q = nqpt;
244*475a782bSnbeams       CeedInt dimstride = nqpt * ncomp * nelem;
245*475a782bSnbeams       CeedInt gradstride = nqpt * nnodes;
2464ce2993fSjeremylt       CeedScalar *grad;
2474ce2993fSjeremylt       ierr = CeedBasisGetGrad(basis, &grad); CeedChk(ierr);
248a8de75f0Sjeremylt       if (tmode == CEED_TRANSPOSE) {
249*475a782bSnbeams         P = nqpt; Q = nnodes;
250*475a782bSnbeams         for (CeedInt d = 0; d < dim; d++) {
2512f86a920SJeremy L Thompson           ierr = CeedTensorContractApply(contract, ncomp, P, nelem, Q,
252*475a782bSnbeams                                          grad + d * gradstride, tmode, add,
253*475a782bSnbeams                                          u + d * dimstride, v); CeedChk(ierr);
254*475a782bSnbeams         }
255*475a782bSnbeams       } else {
256*475a782bSnbeams         for (CeedInt d = 0; d < dim; d++) {
257*475a782bSnbeams           ierr = CeedTensorContractApply(contract, ncomp, P, nelem, Q,
258*475a782bSnbeams                                          grad + d * gradstride, tmode, add,
259*475a782bSnbeams                                          u, v + d * dimstride); CeedChk(ierr);
260*475a782bSnbeams         }
261*475a782bSnbeams       }
262a8de75f0Sjeremylt     }
263a8de75f0Sjeremylt     break;
26484a01de5SJeremy L Thompson     // Retrieve interpolation weights
265a8de75f0Sjeremylt     case CEED_EVAL_WEIGHT: {
266a8de75f0Sjeremylt       if (tmode == CEED_TRANSPOSE)
267c042f62fSJeremy L Thompson         // LCOV_EXCL_START
2684ce2993fSjeremylt         return CeedError(ceed, 1,
269a8de75f0Sjeremylt                          "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE");
270c042f62fSJeremy L Thompson       // LCOV_EXCL_STOP
2714ce2993fSjeremylt       CeedScalar *qweight;
2724ce2993fSjeremylt       ierr = CeedBasisGetQWeights(basis, &qweight); CeedChk(ierr);
273a8de75f0Sjeremylt       for (CeedInt i=0; i<nqpt; i++)
27484a01de5SJeremy L Thompson         for (CeedInt e=0; e<nelem; e++)
27584a01de5SJeremy L Thompson           v[i*nelem + e] = qweight[i];
276a8de75f0Sjeremylt     } break;
277c042f62fSJeremy L Thompson     // LCOV_EXCL_START
27884a01de5SJeremy L Thompson     // Evaluate the divergence to/from the quadrature points
279a8de75f0Sjeremylt     case CEED_EVAL_DIV:
2804ce2993fSjeremylt       return CeedError(ceed, 1, "CEED_EVAL_DIV not supported");
28184a01de5SJeremy L Thompson     // Evaluate the curl to/from the quadrature points
282a8de75f0Sjeremylt     case CEED_EVAL_CURL:
2834ce2993fSjeremylt       return CeedError(ceed, 1, "CEED_EVAL_CURL not supported");
28484a01de5SJeremy L Thompson     // Take no action, BasisApply should not have been called
285a8de75f0Sjeremylt     case CEED_EVAL_NONE:
2864ce2993fSjeremylt       return CeedError(ceed, 1,
287a8de75f0Sjeremylt                        "CEED_EVAL_NONE does not make sense in this context");
288c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
289a8de75f0Sjeremylt     }
290a8de75f0Sjeremylt   }
291aedaa0e5Sjeremylt   if (U) {
292aedaa0e5Sjeremylt     ierr = CeedVectorRestoreArrayRead(U, &u); CeedChk(ierr);
293aedaa0e5Sjeremylt   }
294aedaa0e5Sjeremylt   ierr = CeedVectorRestoreArray(V, &v); CeedChk(ierr);
29521617c04Sjeremylt   return 0;
29621617c04Sjeremylt }
29721617c04Sjeremylt 
29884a01de5SJeremy L Thompson static int CeedBasisDestroyNonTensor_Ref(CeedBasis basis) {
2992f86a920SJeremy L Thompson   int ierr;
3002f86a920SJeremy L Thompson   CeedTensorContract contract;
3012f86a920SJeremy L Thompson   ierr = CeedBasisGetTensorContract(basis, &contract); CeedChk(ierr);
3022f86a920SJeremy L Thompson   ierr = CeedTensorContractDestroy(&contract); CeedChk(ierr);
30384a01de5SJeremy L Thompson   return 0;
30484a01de5SJeremy L Thompson }
30584a01de5SJeremy L Thompson 
30684a01de5SJeremy L Thompson static int CeedBasisDestroyTensor_Ref(CeedBasis basis) {
30784a01de5SJeremy L Thompson   int ierr;
3082f86a920SJeremy L Thompson   CeedTensorContract contract;
3092f86a920SJeremy L Thompson   ierr = CeedBasisGetTensorContract(basis, &contract); CeedChk(ierr);
3102f86a920SJeremy L Thompson   ierr = CeedTensorContractDestroy(&contract); CeedChk(ierr);
3112f86a920SJeremy L Thompson 
31284a01de5SJeremy L Thompson   CeedBasis_Ref *impl;
31384a01de5SJeremy L Thompson   ierr = CeedBasisGetData(basis, (void *)&impl); CeedChk(ierr);
314dfe03796SJeremy L Thompson   ierr = CeedFree(&impl->collograd1d); CeedChk(ierr);
31584a01de5SJeremy L Thompson   ierr = CeedFree(&impl); CeedChk(ierr);
31684a01de5SJeremy L Thompson 
31721617c04Sjeremylt   return 0;
31821617c04Sjeremylt }
31921617c04Sjeremylt 
320667bc5fcSjeremylt int CeedBasisCreateTensorH1_Ref(CeedInt dim, CeedInt P1d,
32121617c04Sjeremylt                                 CeedInt Q1d, const CeedScalar *interp1d,
32221617c04Sjeremylt                                 const CeedScalar *grad1d,
32321617c04Sjeremylt                                 const CeedScalar *qref1d,
32421617c04Sjeremylt                                 const CeedScalar *qweight1d,
32521617c04Sjeremylt                                 CeedBasis basis) {
326fe2413ffSjeremylt   int ierr;
327fe2413ffSjeremylt   Ceed ceed;
328fe2413ffSjeremylt   ierr = CeedBasisGetCeed(basis, &ceed); CeedChk(ierr);
32984a01de5SJeremy L Thompson   CeedBasis_Ref *impl;
33084a01de5SJeremy L Thompson   ierr = CeedCalloc(1, &impl); CeedChk(ierr);
331dfe03796SJeremy L Thompson   // Check for collocated interp
332dfe03796SJeremy L Thompson   if (Q1d == P1d) {
333dfe03796SJeremy L Thompson     bool collocated = 1;
334dfe03796SJeremy L Thompson     for (CeedInt i=0; i<P1d; i++) {
335dfe03796SJeremy L Thompson       collocated = collocated && (fabs(interp1d[i+P1d*i] - 1.0) < 1e-14);
336dfe03796SJeremy L Thompson       for (CeedInt j=0; j<P1d; j++)
337dfe03796SJeremy L Thompson         if (j != i)
338dfe03796SJeremy L Thompson           collocated = collocated && (fabs(interp1d[j+P1d*i]) < 1e-14);
339dfe03796SJeremy L Thompson     }
340dfe03796SJeremy L Thompson     impl->collointerp = collocated;
341dfe03796SJeremy L Thompson   }
342dfe03796SJeremy L Thompson   // Calculate collocated grad
343dfe03796SJeremy L Thompson   if (Q1d >= P1d && !impl->collointerp) {
344dfe03796SJeremy L Thompson     ierr = CeedMalloc(Q1d*Q1d, &impl->collograd1d); CeedChk(ierr);
345dfe03796SJeremy L Thompson     ierr = CeedBasisGetCollocatedGrad(basis, impl->collograd1d); CeedChk(ierr);
346a7bd39daSjeremylt   }
34784a01de5SJeremy L Thompson   ierr = CeedBasisSetData(basis, (void *)&impl); CeedChk(ierr);
348fe2413ffSjeremylt 
3492f86a920SJeremy L Thompson   Ceed parent;
350de686571SJeremy L Thompson   ierr = CeedGetParent(ceed, &parent); CeedChk(ierr);
3512f86a920SJeremy L Thompson   CeedTensorContract contract;
352c71e1dcdSjeremylt   ierr = CeedTensorContractCreate(parent, basis, &contract); CeedChk(ierr);
3532f86a920SJeremy L Thompson   ierr = CeedBasisSetTensorContract(basis, &contract); CeedChk(ierr);
3542f86a920SJeremy L Thompson 
355fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Apply",
356fe2413ffSjeremylt                                 CeedBasisApply_Ref); CeedChk(ierr);
357fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Destroy",
35884a01de5SJeremy L Thompson                                 CeedBasisDestroyTensor_Ref); CeedChk(ierr);
35921617c04Sjeremylt   return 0;
36021617c04Sjeremylt }
361a8de75f0Sjeremylt 
36284a01de5SJeremy L Thompson 
36384a01de5SJeremy L Thompson 
364667bc5fcSjeremylt int CeedBasisCreateH1_Ref(CeedElemTopology topo, CeedInt dim,
3658795c945Sjeremylt                           CeedInt nnodes, CeedInt nqpts,
366a8de75f0Sjeremylt                           const CeedScalar *interp,
367a8de75f0Sjeremylt                           const CeedScalar *grad,
368a8de75f0Sjeremylt                           const CeedScalar *qref,
369a8de75f0Sjeremylt                           const CeedScalar *qweight,
370a8de75f0Sjeremylt                           CeedBasis basis) {
371fe2413ffSjeremylt   int ierr;
372fe2413ffSjeremylt   Ceed ceed;
373fe2413ffSjeremylt   ierr = CeedBasisGetCeed(basis, &ceed); CeedChk(ierr);
374fe2413ffSjeremylt 
375c71e1dcdSjeremylt   Ceed parent;
376c71e1dcdSjeremylt   ierr = CeedGetParent(ceed, &parent); CeedChk(ierr);
3772f86a920SJeremy L Thompson   CeedTensorContract contract;
378c71e1dcdSjeremylt   ierr = CeedTensorContractCreate(parent, basis, &contract); CeedChk(ierr);
3792f86a920SJeremy L Thompson   ierr = CeedBasisSetTensorContract(basis, &contract); CeedChk(ierr);
3802f86a920SJeremy L Thompson 
381fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Apply",
382fe2413ffSjeremylt                                 CeedBasisApply_Ref); CeedChk(ierr);
383fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Destroy",
38484a01de5SJeremy L Thompson                                 CeedBasisDestroyNonTensor_Ref); CeedChk(ierr);
38584a01de5SJeremy L Thompson 
386a8de75f0Sjeremylt   return 0;
387a8de75f0Sjeremylt }
388