xref: /libCEED/rust/libceed-sys/c-src/backends/ref/ceed-ref-basis.c (revision 3d576824e8d990e1f48c6609089904bee9170514)
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 
17*3d576824SJeremy L Thompson #include <ceed.h>
18*3d576824SJeremy L Thompson #include <ceed-backend.h>
19*3d576824SJeremy L Thompson #include <math.h>
20*3d576824SJeremy L Thompson #include <stdbool.h>
21*3d576824SJeremy L Thompson #include <string.h>
2221617c04Sjeremylt #include "ceed-ref.h"
2321617c04Sjeremylt 
24f10650afSjeremylt //------------------------------------------------------------------------------
25f10650afSjeremylt // Basis Apply
26f10650afSjeremylt //------------------------------------------------------------------------------
27d3181881Sjeremylt static int CeedBasisApply_Ref(CeedBasis basis, CeedInt nelem,
28d3181881Sjeremylt                               CeedTransposeMode tmode, CeedEvalMode emode,
29aedaa0e5Sjeremylt                               CeedVector U, CeedVector V) {
3021617c04Sjeremylt   int ierr;
314ce2993fSjeremylt   Ceed ceed;
324ce2993fSjeremylt   ierr = CeedBasisGetCeed(basis, &ceed); CeedChk(ierr);
338795c945Sjeremylt   CeedInt dim, ncomp, nnodes, nqpt;
344ce2993fSjeremylt   ierr = CeedBasisGetDimension(basis, &dim); CeedChk(ierr);
354ce2993fSjeremylt   ierr = CeedBasisGetNumComponents(basis, &ncomp); CeedChk(ierr);
368795c945Sjeremylt   ierr = CeedBasisGetNumNodes(basis, &nnodes); CeedChk(ierr);
374ce2993fSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis, &nqpt); CeedChk(ierr);
382f86a920SJeremy L Thompson   CeedTensorContract contract;
392f86a920SJeremy L Thompson   ierr = CeedBasisGetTensorContract(basis, &contract); CeedChk(ierr);
4021617c04Sjeremylt   const CeedInt add = (tmode == CEED_TRANSPOSE);
41aedaa0e5Sjeremylt   const CeedScalar *u;
42aedaa0e5Sjeremylt   CeedScalar *v;
43a7b7f929Sjeremylt   if (U != CEED_VECTOR_NONE) {
44aedaa0e5Sjeremylt     ierr = CeedVectorGetArrayRead(U, CEED_MEM_HOST, &u); CeedChk(ierr);
45aedaa0e5Sjeremylt   } else if (emode != CEED_EVAL_WEIGHT) {
46c042f62fSJeremy L Thompson     // LCOV_EXCL_START
47aedaa0e5Sjeremylt     return CeedError(ceed, 1,
48aedaa0e5Sjeremylt                      "An input vector is required for this CeedEvalMode");
49c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
50aedaa0e5Sjeremylt   }
51aedaa0e5Sjeremylt   ierr = CeedVectorGetArray(V, CEED_MEM_HOST, &v); CeedChk(ierr);
5221617c04Sjeremylt 
538d94b059Sjeremylt   // Clear v if operating in transpose
5421617c04Sjeremylt   if (tmode == CEED_TRANSPOSE) {
558795c945Sjeremylt     const CeedInt vsize = nelem*ncomp*nnodes;
5621617c04Sjeremylt     for (CeedInt i = 0; i < vsize; i++)
5784a01de5SJeremy L Thompson       v[i] = (CeedScalar) 0.0;
5821617c04Sjeremylt   }
594ce2993fSjeremylt   bool tensorbasis;
60fd364f38SJeremy L Thompson   ierr = CeedBasisIsTensor(basis, &tensorbasis); CeedChk(ierr);
6184a01de5SJeremy L Thompson   // Tensor basis
624ce2993fSjeremylt   if (tensorbasis) {
634ce2993fSjeremylt     CeedInt P1d, Q1d;
644ce2993fSjeremylt     ierr = CeedBasisGetNumNodes1D(basis, &P1d); CeedChk(ierr);
654ce2993fSjeremylt     ierr = CeedBasisGetNumQuadraturePoints1D(basis, &Q1d); CeedChk(ierr);
66a2b73c81Sjeremylt     switch (emode) {
678d94b059Sjeremylt     // Interpolate to/from quadrature points
68a2b73c81Sjeremylt     case CEED_EVAL_INTERP: {
69dfe03796SJeremy L Thompson       CeedBasis_Ref *impl;
70777ff853SJeremy L Thompson       ierr = CeedBasisGetData(basis, &impl); CeedChk(ierr);
71dfe03796SJeremy L Thompson       if (impl->collointerp) {
72dfe03796SJeremy L Thompson         memcpy(v, u, nelem*ncomp*nnodes*sizeof(u[0]));
73dfe03796SJeremy L Thompson       } else {
744ce2993fSjeremylt         CeedInt P = P1d, Q = Q1d;
7521617c04Sjeremylt         if (tmode == CEED_TRANSPOSE) {
764ce2993fSjeremylt           P = Q1d; Q = P1d;
7721617c04Sjeremylt         }
7884a01de5SJeremy L Thompson         CeedInt pre = ncomp*CeedIntPow(P, dim-1), post = nelem;
7984a01de5SJeremy L Thompson         CeedScalar tmp[2][nelem*ncomp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
806c58de82SJeremy L Thompson         const CeedScalar *interp1d;
8100f91b2bSjeremylt         ierr = CeedBasisGetInterp1D(basis, &interp1d); CeedChk(ierr);
8221617c04Sjeremylt         for (CeedInt d=0; d<dim; d++) {
832f86a920SJeremy L Thompson           ierr = CeedTensorContractApply(contract, pre, P, post, Q,
8484a01de5SJeremy L Thompson                                          interp1d, tmode, add&&(d==dim-1),
85dfe03796SJeremy L Thompson                                          d==0?u:tmp[d%2],
86dfe03796SJeremy L Thompson                                          d==dim-1?v:tmp[(d+1)%2]);
8721617c04Sjeremylt           CeedChk(ierr);
8821617c04Sjeremylt           pre /= P;
8921617c04Sjeremylt           post *= Q;
9021617c04Sjeremylt         }
91dfe03796SJeremy L Thompson       }
92a2b73c81Sjeremylt     } break;
938d94b059Sjeremylt     // Evaluate the gradient to/from quadrature points
94a2b73c81Sjeremylt     case CEED_EVAL_GRAD: {
9521617c04Sjeremylt       // In CEED_NOTRANSPOSE mode:
96ecf6354eSJed Brown       // u has shape [dim, ncomp, P^dim, nelem], row-major layout
97ecf6354eSJed Brown       // v has shape [dim, ncomp, Q^dim, nelem], row-major layout
9821617c04Sjeremylt       // In CEED_TRANSPOSE mode, the sizes of u and v are switched.
9984a01de5SJeremy L Thompson       CeedInt P = P1d, Q = Q1d;
10021617c04Sjeremylt       if (tmode == CEED_TRANSPOSE) {
10184a01de5SJeremy L Thompson         P = Q1d, Q = Q1d;
10221617c04Sjeremylt       }
10384a01de5SJeremy L Thompson       CeedBasis_Ref *impl;
104777ff853SJeremy L Thompson       ierr = CeedBasisGetData(basis, &impl); CeedChk(ierr);
10584a01de5SJeremy L Thompson       CeedInt pre = ncomp*CeedIntPow(P, dim-1), post = nelem;
1066c58de82SJeremy L Thompson       const CeedScalar *interp1d;
10700f91b2bSjeremylt       ierr = CeedBasisGetInterp1D(basis, &interp1d); CeedChk(ierr);
108dfe03796SJeremy L Thompson       if (impl->collograd1d) {
109a7bd39daSjeremylt         CeedScalar tmp[2][nelem*ncomp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
110a7bd39daSjeremylt         CeedScalar interp[nelem*ncomp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
11184a01de5SJeremy L Thompson         // Interpolate to quadrature points (NoTranspose)
11284a01de5SJeremy L Thompson         //  or Grad to quadrature points (Transpose)
11321617c04Sjeremylt         for (CeedInt d=0; d<dim; d++) {
1142f86a920SJeremy L Thompson           ierr = CeedTensorContractApply(contract, pre, P, post, Q,
11584a01de5SJeremy L Thompson                                          (tmode == CEED_NOTRANSPOSE
11684a01de5SJeremy L Thompson                                           ? interp1d
117dfe03796SJeremy L Thompson                                           : impl->collograd1d),
11884a01de5SJeremy L Thompson                                          tmode, add&&(d>0),
11984a01de5SJeremy L Thompson                                          (tmode == CEED_NOTRANSPOSE
12084a01de5SJeremy L Thompson                                           ? (d==0?u:tmp[d%2])
12184a01de5SJeremy L Thompson                                           : u + d*nqpt*ncomp*nelem),
12284a01de5SJeremy L Thompson                                          (tmode == CEED_NOTRANSPOSE
12384a01de5SJeremy L Thompson                                           ? (d==dim-1?interp:tmp[(d+1)%2])
12484a01de5SJeremy L Thompson                                           : interp));
12521617c04Sjeremylt           CeedChk(ierr);
12621617c04Sjeremylt           pre /= P;
12721617c04Sjeremylt           post *= Q;
12821617c04Sjeremylt         }
12984a01de5SJeremy L Thompson         // Grad to quadrature points (NoTranspose)
1308795c945Sjeremylt         //  or Interpolate to nodes (Transpose)
13184a01de5SJeremy L Thompson         P = Q1d, Q = Q1d;
13284a01de5SJeremy L Thompson         if (tmode == CEED_TRANSPOSE) {
13384a01de5SJeremy L Thompson           P = Q1d, Q = P1d;
13484a01de5SJeremy L Thompson         }
13584a01de5SJeremy L Thompson         pre = ncomp*CeedIntPow(P, dim-1), post = nelem;
13684a01de5SJeremy L Thompson         for (CeedInt d=0; d<dim; d++) {
1372f86a920SJeremy L Thompson           ierr = CeedTensorContractApply(contract, pre, P, post, Q,
13884a01de5SJeremy L Thompson                                          (tmode == CEED_NOTRANSPOSE
139dfe03796SJeremy L Thompson                                           ? impl->collograd1d
14084a01de5SJeremy L Thompson                                           : interp1d),
14184a01de5SJeremy L Thompson                                          tmode, add&&(d==dim-1),
14284a01de5SJeremy L Thompson                                          (tmode == CEED_NOTRANSPOSE
14384a01de5SJeremy L Thompson                                           ? interp
14484a01de5SJeremy L Thompson                                           : (d==0?interp:tmp[d%2])),
14584a01de5SJeremy L Thompson                                          (tmode == CEED_NOTRANSPOSE
14684a01de5SJeremy L Thompson                                           ? v + d*nqpt*ncomp*nelem
14784a01de5SJeremy L Thompson                                           : (d==dim-1?v:tmp[(d+1)%2])));
14884a01de5SJeremy L Thompson           CeedChk(ierr);
14984a01de5SJeremy L Thompson           pre /= P;
15084a01de5SJeremy L Thompson           post *= Q;
15121617c04Sjeremylt         }
152dfe03796SJeremy L Thompson       } else if (impl->collointerp) { // Qpts collocated with nodes
1536c58de82SJeremy L Thompson         const CeedScalar *grad1d;
15400f91b2bSjeremylt         ierr = CeedBasisGetGrad1D(basis, &grad1d); CeedChk(ierr);
155dfe03796SJeremy L Thompson 
156dfe03796SJeremy L Thompson         // Dim contractions, identity in other directions
157dfe03796SJeremy L Thompson         CeedInt pre = ncomp*CeedIntPow(P, dim-1), post = nelem;
158c6158135Sjeremylt         for (CeedInt d=0; d<dim; d++) {
159dfe03796SJeremy L Thompson           ierr = CeedTensorContractApply(contract, pre, P, post, Q,
160a1dbd226Sjeremylt                                          grad1d, tmode, add&&(d>0),
161dfe03796SJeremy L Thompson                                          tmode == CEED_NOTRANSPOSE
162dfe03796SJeremy L Thompson                                          ? u : u+d*ncomp*nqpt*nelem,
163dfe03796SJeremy L Thompson                                          tmode == CEED_TRANSPOSE
164dfe03796SJeremy L Thompson                                          ? v : v+d*ncomp*nqpt*nelem);
165dfe03796SJeremy L Thompson           CeedChk(ierr);
166c6158135Sjeremylt           pre /= P;
167c6158135Sjeremylt           post *= Q;
168dfe03796SJeremy L Thompson         }
169a7bd39daSjeremylt       } else { // Underintegration, P > Q
1706c58de82SJeremy L Thompson         const CeedScalar *grad1d;
17100f91b2bSjeremylt         ierr = CeedBasisGetGrad1D(basis, &grad1d); CeedChk(ierr);
172a7bd39daSjeremylt 
173a7bd39daSjeremylt         if (tmode == CEED_TRANSPOSE) {
174a7bd39daSjeremylt           P = Q1d, Q = P1d;
175a7bd39daSjeremylt         }
176a7bd39daSjeremylt         CeedScalar tmp[2][nelem*ncomp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
177a7bd39daSjeremylt 
178a7bd39daSjeremylt         // Dim**2 contractions, apply grad when pass == dim
179a7bd39daSjeremylt         for (CeedInt p=0; p<dim; p++) {
180a7bd39daSjeremylt           CeedInt pre = ncomp*CeedIntPow(P, dim-1), post = nelem;
181a7bd39daSjeremylt           for (CeedInt d=0; d<dim; d++) {
182a7bd39daSjeremylt             ierr = CeedTensorContractApply(contract, pre, P, post, Q,
183a7bd39daSjeremylt                                            (p==d)? grad1d : interp1d,
184a7bd39daSjeremylt                                            tmode, add&&(d==dim-1),
185a7bd39daSjeremylt                                            (d == 0
186a7bd39daSjeremylt                                             ? (tmode == CEED_NOTRANSPOSE
187a7bd39daSjeremylt                                                ? u : u+p*ncomp*nqpt*nelem)
188a7bd39daSjeremylt                                             : tmp[d%2]),
189a7bd39daSjeremylt                                            (d == dim-1
190a7bd39daSjeremylt                                             ? (tmode == CEED_TRANSPOSE
191a7bd39daSjeremylt                                                ? v : v+p*ncomp*nqpt*nelem)
192a7bd39daSjeremylt                                             : tmp[(d+1)%2]));
193a7bd39daSjeremylt             CeedChk(ierr);
194a7bd39daSjeremylt             pre /= P;
195a7bd39daSjeremylt             post *= Q;
196a7bd39daSjeremylt           }
197a7bd39daSjeremylt         }
198a7bd39daSjeremylt       }
199a2b73c81Sjeremylt     } break;
2008d94b059Sjeremylt     // Retrieve interpolation weights
201a2b73c81Sjeremylt     case CEED_EVAL_WEIGHT: {
20221617c04Sjeremylt       if (tmode == CEED_TRANSPOSE)
203c042f62fSJeremy L Thompson         // LCOV_EXCL_START
2044ce2993fSjeremylt         return CeedError(ceed, 1,
20521617c04Sjeremylt                          "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE");
206c042f62fSJeremy L Thompson       // LCOV_EXCL_STOP
2074ce2993fSjeremylt       CeedInt Q = Q1d;
2086c58de82SJeremy L Thompson       const CeedScalar *qweight1d;
2094ce2993fSjeremylt       ierr = CeedBasisGetQWeights(basis, &qweight1d); CeedChk(ierr);
21021617c04Sjeremylt       for (CeedInt d=0; d<dim; d++) {
211b5cf12eeSjeremylt         CeedInt pre = CeedIntPow(Q, dim-d-1), post = CeedIntPow(Q, d);
212a2b73c81Sjeremylt         for (CeedInt i=0; i<pre; i++)
213a2b73c81Sjeremylt           for (CeedInt j=0; j<Q; j++)
21484a01de5SJeremy L Thompson             for (CeedInt k=0; k<post; k++) {
21584a01de5SJeremy L Thompson               CeedScalar w = qweight1d[j]
21684a01de5SJeremy L Thompson                              * (d == 0 ? 1 : v[((i*Q + j)*post + k)*nelem]);
21784a01de5SJeremy L Thompson               for (CeedInt e=0; e<nelem; e++)
21884a01de5SJeremy L Thompson                 v[((i*Q + j)*post + k)*nelem + e] = w;
21984a01de5SJeremy L Thompson             }
22021617c04Sjeremylt       }
221a2b73c81Sjeremylt     } break;
222c042f62fSJeremy L Thompson     // LCOV_EXCL_START
2238d94b059Sjeremylt     // Evaluate the divergence to/from the quadrature points
224a2b73c81Sjeremylt     case CEED_EVAL_DIV:
2254ce2993fSjeremylt       return CeedError(ceed, 1, "CEED_EVAL_DIV not supported");
2268d94b059Sjeremylt     // Evaluate the curl to/from the quadrature points
227a2b73c81Sjeremylt     case CEED_EVAL_CURL:
2284ce2993fSjeremylt       return CeedError(ceed, 1, "CEED_EVAL_CURL not supported");
2298d94b059Sjeremylt     // Take no action, BasisApply should not have been called
230a2b73c81Sjeremylt     case CEED_EVAL_NONE:
2314ce2993fSjeremylt       return CeedError(ceed, 1,
2324b8bea3bSJed Brown                        "CEED_EVAL_NONE does not make sense in this context");
233c042f62fSJeremy L Thompson       // LCOV_EXCL_STOP
23421617c04Sjeremylt     }
235a8de75f0Sjeremylt   } else {
236a8de75f0Sjeremylt     // Non-tensor basis
237a8de75f0Sjeremylt     switch (emode) {
23884a01de5SJeremy L Thompson     // Interpolate to/from quadrature points
239a8de75f0Sjeremylt     case CEED_EVAL_INTERP: {
2408795c945Sjeremylt       CeedInt P = nnodes, Q = nqpt;
2416c58de82SJeremy L Thompson       const CeedScalar *interp;
2424ce2993fSjeremylt       ierr = CeedBasisGetInterp(basis, &interp); CeedChk(ierr);
243a8de75f0Sjeremylt       if (tmode == CEED_TRANSPOSE) {
2448795c945Sjeremylt         P = nqpt; Q = nnodes;
245a8de75f0Sjeremylt       }
2462f86a920SJeremy L Thompson       ierr = CeedTensorContractApply(contract, ncomp, P, nelem, Q,
24784a01de5SJeremy L Thompson                                      interp, tmode, add, u, v);
248a8de75f0Sjeremylt       CeedChk(ierr);
249a8de75f0Sjeremylt     }
250a8de75f0Sjeremylt     break;
25184a01de5SJeremy L Thompson     // Evaluate the gradient to/from quadrature points
252a8de75f0Sjeremylt     case CEED_EVAL_GRAD: {
253475a782bSnbeams       CeedInt P = nnodes, Q = nqpt;
254475a782bSnbeams       CeedInt dimstride = nqpt * ncomp * nelem;
255475a782bSnbeams       CeedInt gradstride = nqpt * nnodes;
2566c58de82SJeremy L Thompson       const CeedScalar *grad;
2574ce2993fSjeremylt       ierr = CeedBasisGetGrad(basis, &grad); CeedChk(ierr);
258a8de75f0Sjeremylt       if (tmode == CEED_TRANSPOSE) {
259475a782bSnbeams         P = nqpt; Q = nnodes;
260475a782bSnbeams         for (CeedInt d = 0; d < dim; d++) {
2612f86a920SJeremy L Thompson           ierr = CeedTensorContractApply(contract, ncomp, P, nelem, Q,
262475a782bSnbeams                                          grad + d * gradstride, tmode, add,
263475a782bSnbeams                                          u + d * dimstride, v); CeedChk(ierr);
264475a782bSnbeams         }
265475a782bSnbeams       } else {
266475a782bSnbeams         for (CeedInt d = 0; d < dim; d++) {
267475a782bSnbeams           ierr = CeedTensorContractApply(contract, ncomp, P, nelem, Q,
268475a782bSnbeams                                          grad + d * gradstride, tmode, add,
269475a782bSnbeams                                          u, v + d * dimstride); CeedChk(ierr);
270475a782bSnbeams         }
271475a782bSnbeams       }
272a8de75f0Sjeremylt     }
273a8de75f0Sjeremylt     break;
27484a01de5SJeremy L Thompson     // Retrieve interpolation weights
275a8de75f0Sjeremylt     case CEED_EVAL_WEIGHT: {
276a8de75f0Sjeremylt       if (tmode == CEED_TRANSPOSE)
277c042f62fSJeremy L Thompson         // LCOV_EXCL_START
2784ce2993fSjeremylt         return CeedError(ceed, 1,
279a8de75f0Sjeremylt                          "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE");
280c042f62fSJeremy L Thompson       // LCOV_EXCL_STOP
2816c58de82SJeremy L Thompson       const CeedScalar *qweight;
2824ce2993fSjeremylt       ierr = CeedBasisGetQWeights(basis, &qweight); CeedChk(ierr);
283a8de75f0Sjeremylt       for (CeedInt i=0; i<nqpt; i++)
28484a01de5SJeremy L Thompson         for (CeedInt e=0; e<nelem; e++)
28584a01de5SJeremy L Thompson           v[i*nelem + e] = qweight[i];
286a8de75f0Sjeremylt     } break;
287c042f62fSJeremy L Thompson     // LCOV_EXCL_START
28884a01de5SJeremy L Thompson     // Evaluate the divergence to/from the quadrature points
289a8de75f0Sjeremylt     case CEED_EVAL_DIV:
2904ce2993fSjeremylt       return CeedError(ceed, 1, "CEED_EVAL_DIV not supported");
29184a01de5SJeremy L Thompson     // Evaluate the curl to/from the quadrature points
292a8de75f0Sjeremylt     case CEED_EVAL_CURL:
2934ce2993fSjeremylt       return CeedError(ceed, 1, "CEED_EVAL_CURL not supported");
29484a01de5SJeremy L Thompson     // Take no action, BasisApply should not have been called
295a8de75f0Sjeremylt     case CEED_EVAL_NONE:
2964ce2993fSjeremylt       return CeedError(ceed, 1,
297a8de75f0Sjeremylt                        "CEED_EVAL_NONE does not make sense in this context");
298c042f62fSJeremy L Thompson       // LCOV_EXCL_STOP
299a8de75f0Sjeremylt     }
300a8de75f0Sjeremylt   }
301a7b7f929Sjeremylt   if (U != CEED_VECTOR_NONE) {
302aedaa0e5Sjeremylt     ierr = CeedVectorRestoreArrayRead(U, &u); CeedChk(ierr);
303aedaa0e5Sjeremylt   }
304aedaa0e5Sjeremylt   ierr = CeedVectorRestoreArray(V, &v); CeedChk(ierr);
30521617c04Sjeremylt   return 0;
30621617c04Sjeremylt }
30721617c04Sjeremylt 
308f10650afSjeremylt //------------------------------------------------------------------------------
309f10650afSjeremylt // Basis Destroy Non-Tensor
310f10650afSjeremylt //------------------------------------------------------------------------------
31184a01de5SJeremy L Thompson static int CeedBasisDestroyNonTensor_Ref(CeedBasis basis) {
3122f86a920SJeremy L Thompson   int ierr;
3132f86a920SJeremy L Thompson   CeedTensorContract contract;
3142f86a920SJeremy L Thompson   ierr = CeedBasisGetTensorContract(basis, &contract); CeedChk(ierr);
3152f86a920SJeremy L Thompson   ierr = CeedTensorContractDestroy(&contract); CeedChk(ierr);
31684a01de5SJeremy L Thompson   return 0;
31784a01de5SJeremy L Thompson }
31884a01de5SJeremy L Thompson 
319f10650afSjeremylt //------------------------------------------------------------------------------
320f10650afSjeremylt // Basis Create Non-Tensor
321f10650afSjeremylt //------------------------------------------------------------------------------
322f10650afSjeremylt int CeedBasisCreateH1_Ref(CeedElemTopology topo, CeedInt dim,
323f10650afSjeremylt                           CeedInt nnodes, CeedInt nqpts,
324f10650afSjeremylt                           const CeedScalar *interp,
325f10650afSjeremylt                           const CeedScalar *grad,
326f10650afSjeremylt                           const CeedScalar *qref,
327f10650afSjeremylt                           const CeedScalar *qweight,
328f10650afSjeremylt                           CeedBasis basis) {
329f10650afSjeremylt   int ierr;
330f10650afSjeremylt   Ceed ceed;
331f10650afSjeremylt   ierr = CeedBasisGetCeed(basis, &ceed); CeedChk(ierr);
332f10650afSjeremylt 
333f10650afSjeremylt   Ceed parent;
334f10650afSjeremylt   ierr = CeedGetParent(ceed, &parent); CeedChk(ierr);
335f10650afSjeremylt   CeedTensorContract contract;
336f10650afSjeremylt   ierr = CeedTensorContractCreate(parent, basis, &contract); CeedChk(ierr);
337f10650afSjeremylt   ierr = CeedBasisSetTensorContract(basis, &contract); CeedChk(ierr);
338f10650afSjeremylt 
339f10650afSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Apply",
340f10650afSjeremylt                                 CeedBasisApply_Ref); CeedChk(ierr);
341f10650afSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Destroy",
342f10650afSjeremylt                                 CeedBasisDestroyNonTensor_Ref); CeedChk(ierr);
343f10650afSjeremylt 
344f10650afSjeremylt   return 0;
345f10650afSjeremylt }
346f10650afSjeremylt 
347f10650afSjeremylt //------------------------------------------------------------------------------
348f10650afSjeremylt // Basis Destroy Tensor
349f10650afSjeremylt //------------------------------------------------------------------------------
35084a01de5SJeremy L Thompson static int CeedBasisDestroyTensor_Ref(CeedBasis basis) {
35184a01de5SJeremy L Thompson   int ierr;
3522f86a920SJeremy L Thompson   CeedTensorContract contract;
3532f86a920SJeremy L Thompson   ierr = CeedBasisGetTensorContract(basis, &contract); CeedChk(ierr);
3542f86a920SJeremy L Thompson   ierr = CeedTensorContractDestroy(&contract); CeedChk(ierr);
3552f86a920SJeremy L Thompson 
35684a01de5SJeremy L Thompson   CeedBasis_Ref *impl;
357777ff853SJeremy L Thompson   ierr = CeedBasisGetData(basis, &impl); CeedChk(ierr);
358dfe03796SJeremy L Thompson   ierr = CeedFree(&impl->collograd1d); CeedChk(ierr);
35984a01de5SJeremy L Thompson   ierr = CeedFree(&impl); CeedChk(ierr);
36084a01de5SJeremy L Thompson 
36121617c04Sjeremylt   return 0;
36221617c04Sjeremylt }
36321617c04Sjeremylt 
364f10650afSjeremylt //------------------------------------------------------------------------------
365f10650afSjeremylt // Basis Create Tensor
366f10650afSjeremylt //------------------------------------------------------------------------------
367667bc5fcSjeremylt int CeedBasisCreateTensorH1_Ref(CeedInt dim, CeedInt P1d,
36821617c04Sjeremylt                                 CeedInt Q1d, const CeedScalar *interp1d,
36921617c04Sjeremylt                                 const CeedScalar *grad1d,
37021617c04Sjeremylt                                 const CeedScalar *qref1d,
37121617c04Sjeremylt                                 const CeedScalar *qweight1d,
37221617c04Sjeremylt                                 CeedBasis basis) {
373fe2413ffSjeremylt   int ierr;
374fe2413ffSjeremylt   Ceed ceed;
375fe2413ffSjeremylt   ierr = CeedBasisGetCeed(basis, &ceed); CeedChk(ierr);
37684a01de5SJeremy L Thompson   CeedBasis_Ref *impl;
37784a01de5SJeremy L Thompson   ierr = CeedCalloc(1, &impl); CeedChk(ierr);
378dfe03796SJeremy L Thompson   // Check for collocated interp
379dfe03796SJeremy L Thompson   if (Q1d == P1d) {
380dfe03796SJeremy L Thompson     bool collocated = 1;
381dfe03796SJeremy L Thompson     for (CeedInt i=0; i<P1d; i++) {
382dfe03796SJeremy L Thompson       collocated = collocated && (fabs(interp1d[i+P1d*i] - 1.0) < 1e-14);
383dfe03796SJeremy L Thompson       for (CeedInt j=0; j<P1d; j++)
384dfe03796SJeremy L Thompson         if (j != i)
385dfe03796SJeremy L Thompson           collocated = collocated && (fabs(interp1d[j+P1d*i]) < 1e-14);
386dfe03796SJeremy L Thompson     }
387dfe03796SJeremy L Thompson     impl->collointerp = collocated;
388dfe03796SJeremy L Thompson   }
389dfe03796SJeremy L Thompson   // Calculate collocated grad
390dfe03796SJeremy L Thompson   if (Q1d >= P1d && !impl->collointerp) {
391dfe03796SJeremy L Thompson     ierr = CeedMalloc(Q1d*Q1d, &impl->collograd1d); CeedChk(ierr);
392dfe03796SJeremy L Thompson     ierr = CeedBasisGetCollocatedGrad(basis, impl->collograd1d); CeedChk(ierr);
393a7bd39daSjeremylt   }
394777ff853SJeremy L Thompson   ierr = CeedBasisSetData(basis, impl); CeedChk(ierr);
395fe2413ffSjeremylt 
3962f86a920SJeremy L Thompson   Ceed parent;
397de686571SJeremy L Thompson   ierr = CeedGetParent(ceed, &parent); CeedChk(ierr);
3982f86a920SJeremy L Thompson   CeedTensorContract contract;
399c71e1dcdSjeremylt   ierr = CeedTensorContractCreate(parent, basis, &contract); CeedChk(ierr);
4002f86a920SJeremy L Thompson   ierr = CeedBasisSetTensorContract(basis, &contract); CeedChk(ierr);
4012f86a920SJeremy L Thompson 
402fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Apply",
403fe2413ffSjeremylt                                 CeedBasisApply_Ref); CeedChk(ierr);
404fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Destroy",
40584a01de5SJeremy L Thompson                                 CeedBasisDestroyTensor_Ref); CeedChk(ierr);
40621617c04Sjeremylt   return 0;
40721617c04Sjeremylt }
408a8de75f0Sjeremylt 
409f10650afSjeremylt //------------------------------------------------------------------------------
410