xref: /libCEED/backends/ref/ceed-ref-basis.c (revision c71e1dcdcfce633cdb19fa81aa6735b006eb809d)
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 <string.h>
1821617c04Sjeremylt #include "ceed-ref.h"
1921617c04Sjeremylt 
20d3181881Sjeremylt static int CeedBasisApply_Ref(CeedBasis basis, CeedInt nelem,
21d3181881Sjeremylt                               CeedTransposeMode tmode, CeedEvalMode emode,
22aedaa0e5Sjeremylt                               CeedVector U, CeedVector V) {
2321617c04Sjeremylt   int ierr;
244ce2993fSjeremylt   Ceed ceed;
254ce2993fSjeremylt   ierr = CeedBasisGetCeed(basis, &ceed); CeedChk(ierr);
264ce2993fSjeremylt   CeedInt dim, ncomp, ndof, nqpt;
274ce2993fSjeremylt   ierr = CeedBasisGetDimension(basis, &dim); CeedChk(ierr);
284ce2993fSjeremylt   ierr = CeedBasisGetNumComponents(basis, &ncomp); CeedChk(ierr);
29a8de75f0Sjeremylt   ierr = CeedBasisGetNumNodes(basis, &ndof); CeedChk(ierr);
304ce2993fSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis, &nqpt); CeedChk(ierr);
312f86a920SJeremy L Thompson   CeedTensorContract contract;
322f86a920SJeremy L Thompson   ierr = CeedBasisGetTensorContract(basis, &contract); CeedChk(ierr);
3321617c04Sjeremylt   const CeedInt add = (tmode == CEED_TRANSPOSE);
34aedaa0e5Sjeremylt   const CeedScalar *u;
35aedaa0e5Sjeremylt   CeedScalar *v;
36aedaa0e5Sjeremylt   if (U) {
37aedaa0e5Sjeremylt     ierr = CeedVectorGetArrayRead(U, CEED_MEM_HOST, &u); CeedChk(ierr);
38aedaa0e5Sjeremylt   } else if (emode != CEED_EVAL_WEIGHT) {
39aedaa0e5Sjeremylt     return CeedError(ceed, 1,
40aedaa0e5Sjeremylt                      "An input vector is required for this CeedEvalMode");
41aedaa0e5Sjeremylt   }
42aedaa0e5Sjeremylt   ierr = CeedVectorGetArray(V, CEED_MEM_HOST, &v); CeedChk(ierr);
4321617c04Sjeremylt 
448d94b059Sjeremylt   // Clear v if operating in transpose
4521617c04Sjeremylt   if (tmode == CEED_TRANSPOSE) {
4684a01de5SJeremy L Thompson     const CeedInt vsize = nelem*ncomp*ndof;
4721617c04Sjeremylt     for (CeedInt i = 0; i < vsize; i++)
4884a01de5SJeremy L Thompson       v[i] = (CeedScalar) 0.0;
4921617c04Sjeremylt   }
504ce2993fSjeremylt   bool tensorbasis;
514ce2993fSjeremylt   ierr = CeedBasisGetTensorStatus(basis, &tensorbasis); CeedChk(ierr);
5284a01de5SJeremy L Thompson   // Tensor basis
534ce2993fSjeremylt   if (tensorbasis) {
544ce2993fSjeremylt     CeedInt P1d, Q1d;
554ce2993fSjeremylt     ierr = CeedBasisGetNumNodes1D(basis, &P1d); CeedChk(ierr);
564ce2993fSjeremylt     ierr = CeedBasisGetNumQuadraturePoints1D(basis, &Q1d); CeedChk(ierr);
57a2b73c81Sjeremylt     switch (emode) {
588d94b059Sjeremylt     // Interpolate to/from quadrature points
59a2b73c81Sjeremylt     case CEED_EVAL_INTERP: {
604ce2993fSjeremylt       CeedInt P = P1d, Q = Q1d;
6121617c04Sjeremylt       if (tmode == CEED_TRANSPOSE) {
624ce2993fSjeremylt         P = Q1d; Q = P1d;
6321617c04Sjeremylt       }
6484a01de5SJeremy L Thompson       CeedInt pre = ncomp*CeedIntPow(P, dim-1), post = nelem;
6584a01de5SJeremy L Thompson       CeedScalar tmp[2][nelem*ncomp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
664ce2993fSjeremylt       CeedScalar *interp1d;
674ce2993fSjeremylt       ierr = CeedBasisGetInterp(basis, &interp1d); CeedChk(ierr);
6821617c04Sjeremylt       for (CeedInt d=0; d<dim; d++) {
692f86a920SJeremy L Thompson         ierr = CeedTensorContractApply(contract, pre, P, post, Q,
7084a01de5SJeremy L Thompson                                        interp1d, tmode, add&&(d==dim-1),
7121617c04Sjeremylt                                        d==0?u:tmp[d%2], d==dim-1?v:tmp[(d+1)%2]);
7221617c04Sjeremylt         CeedChk(ierr);
7321617c04Sjeremylt         pre /= P;
7421617c04Sjeremylt         post *= Q;
7521617c04Sjeremylt       }
76a2b73c81Sjeremylt     } break;
778d94b059Sjeremylt     // Evaluate the gradient to/from quadrature points
78a2b73c81Sjeremylt     case CEED_EVAL_GRAD: {
7921617c04Sjeremylt       // In CEED_NOTRANSPOSE mode:
80ecf6354eSJed Brown       // u has shape [dim, ncomp, P^dim, nelem], row-major layout
81ecf6354eSJed Brown       // v has shape [dim, ncomp, Q^dim, nelem], row-major layout
8221617c04Sjeremylt       // In CEED_TRANSPOSE mode, the sizes of u and v are switched.
8384a01de5SJeremy L Thompson       CeedInt P = P1d, Q = Q1d;
8421617c04Sjeremylt       if (tmode == CEED_TRANSPOSE) {
8584a01de5SJeremy L Thompson         P = Q1d, Q = Q1d;
8621617c04Sjeremylt       }
8784a01de5SJeremy L Thompson       CeedBasis_Ref *impl;
8884a01de5SJeremy L Thompson       ierr = CeedBasisGetData(basis, (void *)&impl); CeedChk(ierr);
8984a01de5SJeremy L Thompson       CeedScalar interp[nelem*ncomp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
9084a01de5SJeremy L Thompson       CeedInt pre = ncomp*CeedIntPow(P, dim-1), post = nelem;
9184a01de5SJeremy L Thompson       CeedScalar tmp[2][nelem*ncomp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
9284a01de5SJeremy L Thompson       CeedScalar *interp1d;
934ce2993fSjeremylt       ierr = CeedBasisGetInterp(basis, &interp1d); CeedChk(ierr);
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)
11384a01de5SJeremy L Thompson       //  or Interpolate to dofs (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       }
135a2b73c81Sjeremylt     } break;
1368d94b059Sjeremylt     // Retrieve interpolation weights
137a2b73c81Sjeremylt     case CEED_EVAL_WEIGHT: {
13821617c04Sjeremylt       if (tmode == CEED_TRANSPOSE)
1394ce2993fSjeremylt         return CeedError(ceed, 1,
14021617c04Sjeremylt                          "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE");
1414ce2993fSjeremylt       CeedInt Q = Q1d;
1424ce2993fSjeremylt       CeedScalar *qweight1d;
1434ce2993fSjeremylt       ierr = CeedBasisGetQWeights(basis, &qweight1d); CeedChk(ierr);
14421617c04Sjeremylt       for (CeedInt d=0; d<dim; d++) {
145b5cf12eeSjeremylt         CeedInt pre = CeedIntPow(Q, dim-d-1), post = CeedIntPow(Q, d);
146a2b73c81Sjeremylt         for (CeedInt i=0; i<pre; i++)
147a2b73c81Sjeremylt           for (CeedInt j=0; j<Q; j++)
14884a01de5SJeremy L Thompson             for (CeedInt k=0; k<post; k++) {
14984a01de5SJeremy L Thompson               CeedScalar w = qweight1d[j]
15084a01de5SJeremy L Thompson                              * (d == 0 ? 1 : v[((i*Q + j)*post + k)*nelem]);
15184a01de5SJeremy L Thompson               for (CeedInt e=0; e<nelem; e++)
15284a01de5SJeremy L Thompson                 v[((i*Q + j)*post + k)*nelem + e] = w;
15384a01de5SJeremy L Thompson             }
15421617c04Sjeremylt       }
155a2b73c81Sjeremylt     } break;
1568d94b059Sjeremylt     // Evaluate the divergence to/from the quadrature points
157a2b73c81Sjeremylt     case CEED_EVAL_DIV:
1584ce2993fSjeremylt       return CeedError(ceed, 1, "CEED_EVAL_DIV not supported");
1598d94b059Sjeremylt     // Evaluate the curl to/from the quadrature points
160a2b73c81Sjeremylt     case CEED_EVAL_CURL:
1614ce2993fSjeremylt       return CeedError(ceed, 1, "CEED_EVAL_CURL not supported");
1628d94b059Sjeremylt     // Take no action, BasisApply should not have been called
163a2b73c81Sjeremylt     case CEED_EVAL_NONE:
1644ce2993fSjeremylt       return CeedError(ceed, 1,
1654b8bea3bSJed Brown                        "CEED_EVAL_NONE does not make sense in this context");
16621617c04Sjeremylt     }
167a8de75f0Sjeremylt   } else {
168a8de75f0Sjeremylt     // Non-tensor basis
169a8de75f0Sjeremylt     switch (emode) {
17084a01de5SJeremy L Thompson     // Interpolate to/from quadrature points
171a8de75f0Sjeremylt     case CEED_EVAL_INTERP: {
1724ce2993fSjeremylt       CeedInt P = ndof, Q = nqpt;
1734ce2993fSjeremylt       CeedScalar *interp;
1744ce2993fSjeremylt       ierr = CeedBasisGetInterp(basis, &interp); CeedChk(ierr);
175a8de75f0Sjeremylt       if (tmode == CEED_TRANSPOSE) {
1764ce2993fSjeremylt         P = nqpt; Q = ndof;
177a8de75f0Sjeremylt       }
1782f86a920SJeremy L Thompson       ierr = CeedTensorContractApply(contract, ncomp, P, nelem, Q,
17984a01de5SJeremy L Thompson                                      interp, tmode, add, u, v);
180a8de75f0Sjeremylt       CeedChk(ierr);
181a8de75f0Sjeremylt     }
182a8de75f0Sjeremylt     break;
18384a01de5SJeremy L Thompson     // Evaluate the gradient to/from quadrature points
184a8de75f0Sjeremylt     case CEED_EVAL_GRAD: {
1854ce2993fSjeremylt       CeedInt P = ndof, Q = dim*nqpt;
1864ce2993fSjeremylt       CeedScalar *grad;
1874ce2993fSjeremylt       ierr = CeedBasisGetGrad(basis, &grad); CeedChk(ierr);
188a8de75f0Sjeremylt       if (tmode == CEED_TRANSPOSE) {
1894ce2993fSjeremylt         P = dim*nqpt; Q = ndof;
190a8de75f0Sjeremylt       }
1912f86a920SJeremy L Thompson       ierr = CeedTensorContractApply(contract, ncomp, P, nelem, Q,
19284a01de5SJeremy L Thompson                                      grad, tmode, add, u, v);
193a8de75f0Sjeremylt       CeedChk(ierr);
194a8de75f0Sjeremylt     }
195a8de75f0Sjeremylt     break;
19684a01de5SJeremy L Thompson     // Retrieve interpolation weights
197a8de75f0Sjeremylt     case CEED_EVAL_WEIGHT: {
198a8de75f0Sjeremylt       if (tmode == CEED_TRANSPOSE)
1994ce2993fSjeremylt         return CeedError(ceed, 1,
200a8de75f0Sjeremylt                          "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE");
2014ce2993fSjeremylt       CeedScalar *qweight;
2024ce2993fSjeremylt       ierr = CeedBasisGetQWeights(basis, &qweight); CeedChk(ierr);
203a8de75f0Sjeremylt       for (CeedInt i=0; i<nqpt; i++)
20484a01de5SJeremy L Thompson         for (CeedInt e=0; e<nelem; e++)
20584a01de5SJeremy L Thompson           v[i*nelem + e] = qweight[i];
206a8de75f0Sjeremylt     } break;
20784a01de5SJeremy L Thompson     // Evaluate the divergence to/from the quadrature points
208a8de75f0Sjeremylt     case CEED_EVAL_DIV:
2094ce2993fSjeremylt       return CeedError(ceed, 1, "CEED_EVAL_DIV not supported");
21084a01de5SJeremy L Thompson     // Evaluate the curl to/from the quadrature points
211a8de75f0Sjeremylt     case CEED_EVAL_CURL:
2124ce2993fSjeremylt       return CeedError(ceed, 1, "CEED_EVAL_CURL not supported");
21384a01de5SJeremy L Thompson     // Take no action, BasisApply should not have been called
214a8de75f0Sjeremylt     case CEED_EVAL_NONE:
2154ce2993fSjeremylt       return CeedError(ceed, 1,
216a8de75f0Sjeremylt                        "CEED_EVAL_NONE does not make sense in this context");
217a8de75f0Sjeremylt     }
218a8de75f0Sjeremylt   }
219aedaa0e5Sjeremylt   if (U) {
220aedaa0e5Sjeremylt     ierr = CeedVectorRestoreArrayRead(U, &u); CeedChk(ierr);
221aedaa0e5Sjeremylt   }
222aedaa0e5Sjeremylt   ierr = CeedVectorRestoreArray(V, &v); CeedChk(ierr);
22321617c04Sjeremylt   return 0;
22421617c04Sjeremylt }
22521617c04Sjeremylt 
22684a01de5SJeremy L Thompson static int CeedBasisDestroyNonTensor_Ref(CeedBasis basis) {
2272f86a920SJeremy L Thompson   int ierr;
2282f86a920SJeremy L Thompson   CeedTensorContract contract;
2292f86a920SJeremy L Thompson   ierr = CeedBasisGetTensorContract(basis, &contract); CeedChk(ierr);
2302f86a920SJeremy L Thompson   ierr = CeedTensorContractDestroy(&contract); CeedChk(ierr);
23184a01de5SJeremy L Thompson   return 0;
23284a01de5SJeremy L Thompson }
23384a01de5SJeremy L Thompson 
23484a01de5SJeremy L Thompson static int CeedBasisDestroyTensor_Ref(CeedBasis basis) {
23584a01de5SJeremy L Thompson   int ierr;
2362f86a920SJeremy L Thompson   CeedTensorContract contract;
2372f86a920SJeremy L Thompson   ierr = CeedBasisGetTensorContract(basis, &contract); CeedChk(ierr);
2382f86a920SJeremy L Thompson   ierr = CeedTensorContractDestroy(&contract); CeedChk(ierr);
2392f86a920SJeremy L Thompson 
24084a01de5SJeremy L Thompson   CeedBasis_Ref *impl;
24184a01de5SJeremy L Thompson   ierr = CeedBasisGetData(basis, (void *)&impl); CeedChk(ierr);
24284a01de5SJeremy L Thompson   ierr = CeedFree(&impl->colograd1d); CeedChk(ierr);
24384a01de5SJeremy L Thompson   ierr = CeedFree(&impl); CeedChk(ierr);
24484a01de5SJeremy L Thompson 
24521617c04Sjeremylt   return 0;
24621617c04Sjeremylt }
24721617c04Sjeremylt 
248667bc5fcSjeremylt int CeedBasisCreateTensorH1_Ref(CeedInt dim, CeedInt P1d,
24921617c04Sjeremylt                                 CeedInt Q1d, const CeedScalar *interp1d,
25021617c04Sjeremylt                                 const CeedScalar *grad1d,
25121617c04Sjeremylt                                 const CeedScalar *qref1d,
25221617c04Sjeremylt                                 const CeedScalar *qweight1d,
25321617c04Sjeremylt                                 CeedBasis basis) {
254fe2413ffSjeremylt   int ierr;
255fe2413ffSjeremylt   Ceed ceed;
256fe2413ffSjeremylt   ierr = CeedBasisGetCeed(basis, &ceed); CeedChk(ierr);
25784a01de5SJeremy L Thompson   CeedBasis_Ref *impl;
25884a01de5SJeremy L Thompson   ierr = CeedCalloc(1, &impl); CeedChk(ierr);
25984a01de5SJeremy L Thompson   ierr = CeedMalloc(Q1d*Q1d, &impl->colograd1d); CeedChk(ierr);
26084a01de5SJeremy L Thompson   ierr = CeedBasisGetCollocatedGrad(basis, impl->colograd1d); CeedChk(ierr);
26184a01de5SJeremy L Thompson   ierr = CeedBasisSetData(basis, (void *)&impl); CeedChk(ierr);
262fe2413ffSjeremylt 
2632f86a920SJeremy L Thompson   Ceed parent;
264de686571SJeremy L Thompson   ierr = CeedGetParent(ceed, &parent); CeedChk(ierr);
2652f86a920SJeremy L Thompson   CeedTensorContract contract;
266*c71e1dcdSjeremylt   ierr = CeedTensorContractCreate(parent, basis, &contract); CeedChk(ierr);
2672f86a920SJeremy L Thompson   ierr = CeedBasisSetTensorContract(basis, &contract); CeedChk(ierr);
2682f86a920SJeremy L Thompson 
269fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Apply",
270fe2413ffSjeremylt                                 CeedBasisApply_Ref); CeedChk(ierr);
271fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Destroy",
27284a01de5SJeremy L Thompson                                 CeedBasisDestroyTensor_Ref); CeedChk(ierr);
27321617c04Sjeremylt   return 0;
27421617c04Sjeremylt }
275a8de75f0Sjeremylt 
27684a01de5SJeremy L Thompson 
27784a01de5SJeremy L Thompson 
278667bc5fcSjeremylt int CeedBasisCreateH1_Ref(CeedElemTopology topo, CeedInt dim,
279a8de75f0Sjeremylt                           CeedInt ndof, CeedInt nqpts,
280a8de75f0Sjeremylt                           const CeedScalar *interp,
281a8de75f0Sjeremylt                           const CeedScalar *grad,
282a8de75f0Sjeremylt                           const CeedScalar *qref,
283a8de75f0Sjeremylt                           const CeedScalar *qweight,
284a8de75f0Sjeremylt                           CeedBasis basis) {
285fe2413ffSjeremylt   int ierr;
286fe2413ffSjeremylt   Ceed ceed;
287fe2413ffSjeremylt   ierr = CeedBasisGetCeed(basis, &ceed); CeedChk(ierr);
288fe2413ffSjeremylt 
289*c71e1dcdSjeremylt   Ceed parent;
290*c71e1dcdSjeremylt   ierr = CeedGetParent(ceed, &parent); CeedChk(ierr);
2912f86a920SJeremy L Thompson   CeedTensorContract contract;
292*c71e1dcdSjeremylt   ierr = CeedTensorContractCreate(parent, basis, &contract); CeedChk(ierr);
2932f86a920SJeremy L Thompson   ierr = CeedBasisSetTensorContract(basis, &contract); CeedChk(ierr);
2942f86a920SJeremy L Thompson 
295fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Apply",
296fe2413ffSjeremylt                                 CeedBasisApply_Ref); CeedChk(ierr);
297fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Destroy",
29884a01de5SJeremy L Thompson                                 CeedBasisDestroyNonTensor_Ref); CeedChk(ierr);
29984a01de5SJeremy L Thompson 
300a8de75f0Sjeremylt   return 0;
301a8de75f0Sjeremylt }
302