xref: /libCEED/rust/libceed-sys/c-src/backends/ref/ceed-ref-basis.c (revision fe2413ff2a5f6e0d0808f191532abb277c4b8bc7)
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 
2021617c04Sjeremylt // Contracts on the middle index
2121617c04Sjeremylt // NOTRANSPOSE: V_ajc = T_jb U_abc
2221617c04Sjeremylt // TRANSPOSE:   V_ajc = T_bj U_abc
2321617c04Sjeremylt // If Add != 0, "=" is replaced by "+="
24e6e9a80eSjeremylt static int CeedTensorContract_Ref(Ceed ceed, CeedInt A, CeedInt B, CeedInt C, CeedInt J,
2512170c1eSJed Brown                                   const CeedScalar *restrict t, CeedTransposeMode tmode,
2621617c04Sjeremylt                                   const CeedInt Add,
2712170c1eSJed Brown                                   const CeedScalar *restrict u, CeedScalar *restrict v) {
2821617c04Sjeremylt   CeedInt tstride0 = B, tstride1 = 1;
2921617c04Sjeremylt   if (tmode == CEED_TRANSPOSE) {
3021617c04Sjeremylt     tstride0 = 1; tstride1 = J;
3121617c04Sjeremylt   }
3221617c04Sjeremylt 
33a2b73c81Sjeremylt   if (!Add)
34a2b73c81Sjeremylt     for (CeedInt q=0; q<A*J*C; q++)
351c19f432SSteven Roberts       v[q] = (CeedScalar) 0.0;
361c19f432SSteven Roberts 
37a2b73c81Sjeremylt   for (CeedInt a=0; a<A; a++)
38a2b73c81Sjeremylt     for (CeedInt b=0; b<B; b++)
391c19f432SSteven Roberts       for (CeedInt j=0; j<J; j++) {
401c19f432SSteven Roberts         CeedScalar tq = t[j*tstride0 + b*tstride1];
41a2b73c81Sjeremylt         for (CeedInt c=0; c<C; c++)
42282be9a0SSteven Roberts           v[(a*J+j)*C+c] += tq * u[(a*B+b)*C+c];
4321617c04Sjeremylt       }
4421617c04Sjeremylt   return 0;
4521617c04Sjeremylt }
4621617c04Sjeremylt 
47d3181881Sjeremylt static int CeedBasisApply_Ref(CeedBasis basis, CeedInt nelem,
48d3181881Sjeremylt                               CeedTransposeMode tmode, CeedEvalMode emode,
4921617c04Sjeremylt                               const CeedScalar *u, CeedScalar *v) {
5021617c04Sjeremylt   int ierr;
514ce2993fSjeremylt   Ceed ceed;
524ce2993fSjeremylt   ierr = CeedBasisGetCeed(basis, &ceed); CeedChk(ierr);
534ce2993fSjeremylt   CeedInt dim, ncomp, ndof, nqpt;
544ce2993fSjeremylt   ierr = CeedBasisGetDimension(basis, &dim); CeedChk(ierr);
554ce2993fSjeremylt   ierr = CeedBasisGetNumComponents(basis, &ncomp); CeedChk(ierr);
56a8de75f0Sjeremylt   ierr = CeedBasisGetNumNodes(basis, &ndof); CeedChk(ierr);
574ce2993fSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis, &nqpt); CeedChk(ierr);
5821617c04Sjeremylt   const CeedInt add = (tmode == CEED_TRANSPOSE);
5921617c04Sjeremylt 
60c44a85f4Sjeremylt   if (nelem != 1)
614ce2993fSjeremylt     return CeedError(ceed, 1,
62c44a85f4Sjeremylt                      "This backend does not support BasisApply for multiple elements");
63c44a85f4Sjeremylt 
648d94b059Sjeremylt   // Clear v if operating in transpose
6521617c04Sjeremylt   if (tmode == CEED_TRANSPOSE) {
66a8de75f0Sjeremylt     const CeedInt vsize = ncomp*ndof;
6721617c04Sjeremylt     for (CeedInt i = 0; i < vsize; i++)
6821617c04Sjeremylt       v[i] = (CeedScalar) 0;
6921617c04Sjeremylt   }
70a8de75f0Sjeremylt   // Tensor basis
714ce2993fSjeremylt   bool tensorbasis;
724ce2993fSjeremylt   ierr = CeedBasisGetTensorStatus(basis, &tensorbasis); CeedChk(ierr);
734ce2993fSjeremylt   if (tensorbasis) {
744ce2993fSjeremylt     CeedInt P1d, Q1d;
754ce2993fSjeremylt     ierr = CeedBasisGetNumNodes1D(basis, &P1d); CeedChk(ierr);
764ce2993fSjeremylt     ierr = CeedBasisGetNumQuadraturePoints1D(basis, &Q1d); CeedChk(ierr);
77a2b73c81Sjeremylt     switch (emode) {
788d94b059Sjeremylt     // Interpolate to/from quadrature points
79a2b73c81Sjeremylt     case CEED_EVAL_INTERP: {
804ce2993fSjeremylt       CeedInt P = P1d, Q = Q1d;
8121617c04Sjeremylt       if (tmode == CEED_TRANSPOSE) {
824ce2993fSjeremylt         P = Q1d; Q = P1d;
8321617c04Sjeremylt       }
84b5cf12eeSjeremylt       CeedInt pre = ncomp*CeedIntPow(P, dim-1), post = 1;
85b5cf12eeSjeremylt       CeedScalar tmp[2][ncomp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
864ce2993fSjeremylt       CeedScalar *interp1d;
874ce2993fSjeremylt       ierr = CeedBasisGetInterp(basis, &interp1d); CeedChk(ierr);
8821617c04Sjeremylt       for (CeedInt d=0; d<dim; d++) {
894ce2993fSjeremylt         ierr = CeedTensorContract_Ref(ceed, pre, P, post, Q, interp1d,
9021617c04Sjeremylt                                       tmode, add&&(d==dim-1),
9121617c04Sjeremylt                                       d==0?u:tmp[d%2], d==dim-1?v:tmp[(d+1)%2]);
9221617c04Sjeremylt         CeedChk(ierr);
9321617c04Sjeremylt         pre /= P;
9421617c04Sjeremylt         post *= Q;
9521617c04Sjeremylt       }
96a2b73c81Sjeremylt     } break;
978d94b059Sjeremylt     // Evaluate the gradient to/from quadrature points
98a2b73c81Sjeremylt     case CEED_EVAL_GRAD: {
994ce2993fSjeremylt       CeedInt P = P1d, Q = Q1d;
10021617c04Sjeremylt       // In CEED_NOTRANSPOSE mode:
101ecf6354eSJed Brown       // u has shape [dim, ncomp, P^dim, nelem], row-major layout
102ecf6354eSJed Brown       // v has shape [dim, ncomp, Q^dim, nelem], row-major layout
10321617c04Sjeremylt       // In CEED_TRANSPOSE mode, the sizes of u and v are switched.
10421617c04Sjeremylt       if (tmode == CEED_TRANSPOSE) {
1054ce2993fSjeremylt         P = Q1d, Q = P1d;
10621617c04Sjeremylt       }
107b5cf12eeSjeremylt       CeedScalar tmp[2][ncomp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
1084ce2993fSjeremylt       CeedScalar *interp1d, *grad1d;
1094ce2993fSjeremylt       ierr = CeedBasisGetInterp(basis, &interp1d); CeedChk(ierr);
1104ce2993fSjeremylt       ierr = CeedBasisGetGrad(basis, &grad1d); CeedChk(ierr);
11121617c04Sjeremylt       for (CeedInt p = 0; p < dim; p++) {
112b5cf12eeSjeremylt         CeedInt pre = ncomp*CeedIntPow(P, dim-1), post = 1;
11321617c04Sjeremylt         for (CeedInt d=0; d<dim; d++) {
1144ce2993fSjeremylt           ierr = CeedTensorContract_Ref(ceed, pre, P, post, Q,
1154ce2993fSjeremylt                                         (p==d)?grad1d:interp1d,
11621617c04Sjeremylt                                         tmode, add&&(d==dim-1),
1174b8bea3bSJed Brown                                         (d == 0
118a2b73c81Sjeremylt                                          ? (tmode==CEED_NOTRANSPOSE?u:u+p*ncomp*nqpt)
1194b8bea3bSJed Brown                                          : tmp[d%2]),
1204b8bea3bSJed Brown                                         (d == dim-1
121a2b73c81Sjeremylt                                          ? (tmode==CEED_TRANSPOSE?v:v+p*ncomp*nqpt)
1224b8bea3bSJed Brown                                          : tmp[(d+1)%2]));
12321617c04Sjeremylt           CeedChk(ierr);
12421617c04Sjeremylt           pre /= P;
12521617c04Sjeremylt           post *= Q;
12621617c04Sjeremylt         }
12721617c04Sjeremylt       }
128a2b73c81Sjeremylt     } break;
1298d94b059Sjeremylt     // Retrieve interpolation weights
130a2b73c81Sjeremylt     case CEED_EVAL_WEIGHT: {
13121617c04Sjeremylt       if (tmode == CEED_TRANSPOSE)
1324ce2993fSjeremylt         return CeedError(ceed, 1,
13321617c04Sjeremylt                          "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE");
1344ce2993fSjeremylt       CeedInt Q = Q1d;
1354ce2993fSjeremylt       CeedScalar *qweight1d;
1364ce2993fSjeremylt       ierr = CeedBasisGetQWeights(basis, &qweight1d); CeedChk(ierr);
13721617c04Sjeremylt       for (CeedInt d=0; d<dim; d++) {
138b5cf12eeSjeremylt         CeedInt pre = CeedIntPow(Q, dim-d-1), post = CeedIntPow(Q, d);
139a2b73c81Sjeremylt         for (CeedInt i=0; i<pre; i++)
140a2b73c81Sjeremylt           for (CeedInt j=0; j<Q; j++)
141a2b73c81Sjeremylt             for (CeedInt k=0; k<post; k++)
1424ce2993fSjeremylt               v[(i*Q + j)*post + k] = qweight1d[j]
14321617c04Sjeremylt                                       * (d == 0 ? 1 : v[(i*Q + j)*post + k]);
14421617c04Sjeremylt       }
145a2b73c81Sjeremylt     } break;
1468d94b059Sjeremylt     // Evaluate the divergence to/from the quadrature points
147a2b73c81Sjeremylt     case CEED_EVAL_DIV:
1484ce2993fSjeremylt       return CeedError(ceed, 1, "CEED_EVAL_DIV not supported");
1498d94b059Sjeremylt     // Evaluate the curl to/from the quadrature points
150a2b73c81Sjeremylt     case CEED_EVAL_CURL:
1514ce2993fSjeremylt       return CeedError(ceed, 1, "CEED_EVAL_CURL not supported");
1528d94b059Sjeremylt     // Take no action, BasisApply should not have been called
153a2b73c81Sjeremylt     case CEED_EVAL_NONE:
1544ce2993fSjeremylt       return CeedError(ceed, 1,
1554b8bea3bSJed Brown                        "CEED_EVAL_NONE does not make sense in this context");
15621617c04Sjeremylt     }
157a8de75f0Sjeremylt   } else {
158a8de75f0Sjeremylt     // Non-tensor basis
159a8de75f0Sjeremylt     switch (emode) {
160a8de75f0Sjeremylt     case CEED_EVAL_INTERP: {
1614ce2993fSjeremylt       CeedInt P = ndof, Q = nqpt;
1624ce2993fSjeremylt       CeedScalar *interp;
1634ce2993fSjeremylt       ierr = CeedBasisGetInterp(basis, &interp); CeedChk(ierr);
164a8de75f0Sjeremylt       if (tmode == CEED_TRANSPOSE) {
1654ce2993fSjeremylt         P = nqpt; Q = ndof;
166a8de75f0Sjeremylt       }
1674ce2993fSjeremylt       ierr = CeedTensorContract_Ref(ceed, ncomp, P, 1, Q, interp,
168a8de75f0Sjeremylt                                     tmode, add, u, v);
169a8de75f0Sjeremylt       CeedChk(ierr);
170a8de75f0Sjeremylt     }
171a8de75f0Sjeremylt     break;
172a8de75f0Sjeremylt     case CEED_EVAL_GRAD: {
1734ce2993fSjeremylt       CeedInt P = ndof, Q = dim*nqpt;
1744ce2993fSjeremylt       CeedScalar *grad;
1754ce2993fSjeremylt       ierr = CeedBasisGetGrad(basis, &grad); CeedChk(ierr);
176a8de75f0Sjeremylt       if (tmode == CEED_TRANSPOSE) {
1774ce2993fSjeremylt         P = dim*nqpt; Q = ndof;
178a8de75f0Sjeremylt       }
1794ce2993fSjeremylt       ierr = CeedTensorContract_Ref(ceed, ncomp, P, 1, Q, grad,
180a8de75f0Sjeremylt                                     tmode, add, u, v);
181a8de75f0Sjeremylt       CeedChk(ierr);
182a8de75f0Sjeremylt     }
183a8de75f0Sjeremylt     break;
184a8de75f0Sjeremylt     case CEED_EVAL_WEIGHT: {
185a8de75f0Sjeremylt       if (tmode == CEED_TRANSPOSE)
1864ce2993fSjeremylt         return CeedError(ceed, 1,
187a8de75f0Sjeremylt                          "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE");
1884ce2993fSjeremylt       CeedScalar *qweight;
1894ce2993fSjeremylt       ierr = CeedBasisGetQWeights(basis, &qweight); CeedChk(ierr);
190a8de75f0Sjeremylt       for (CeedInt i=0; i<nqpt; i++)
1914ce2993fSjeremylt         v[i] = qweight[i];
192a8de75f0Sjeremylt     } break;
193a8de75f0Sjeremylt     case CEED_EVAL_DIV:
1944ce2993fSjeremylt       return CeedError(ceed, 1, "CEED_EVAL_DIV not supported");
195a8de75f0Sjeremylt     case CEED_EVAL_CURL:
1964ce2993fSjeremylt       return CeedError(ceed, 1, "CEED_EVAL_CURL not supported");
197a8de75f0Sjeremylt     case CEED_EVAL_NONE:
1984ce2993fSjeremylt       return CeedError(ceed, 1,
199a8de75f0Sjeremylt                        "CEED_EVAL_NONE does not make sense in this context");
200a8de75f0Sjeremylt     }
201a8de75f0Sjeremylt   }
20221617c04Sjeremylt   return 0;
20321617c04Sjeremylt }
20421617c04Sjeremylt 
20521617c04Sjeremylt static int CeedBasisDestroy_Ref(CeedBasis basis) {
20621617c04Sjeremylt   return 0;
20721617c04Sjeremylt }
20821617c04Sjeremylt 
209667bc5fcSjeremylt int CeedBasisCreateTensorH1_Ref(CeedInt dim, CeedInt P1d,
21021617c04Sjeremylt                                 CeedInt Q1d, const CeedScalar *interp1d,
21121617c04Sjeremylt                                 const CeedScalar *grad1d,
21221617c04Sjeremylt                                 const CeedScalar *qref1d,
21321617c04Sjeremylt                                 const CeedScalar *qweight1d,
21421617c04Sjeremylt                                 CeedBasis basis) {
215*fe2413ffSjeremylt   int ierr;
216*fe2413ffSjeremylt   Ceed ceed;
217*fe2413ffSjeremylt   ierr = CeedBasisGetCeed(basis, &ceed); CeedChk(ierr);
218*fe2413ffSjeremylt 
219*fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Apply",
220*fe2413ffSjeremylt                                 CeedBasisApply_Ref); CeedChk(ierr);
221*fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Destroy",
222*fe2413ffSjeremylt                                 CeedBasisDestroy_Ref); CeedChk(ierr);
22321617c04Sjeremylt   return 0;
22421617c04Sjeremylt }
225a8de75f0Sjeremylt 
226667bc5fcSjeremylt int CeedBasisCreateH1_Ref(CeedElemTopology topo, CeedInt dim,
227a8de75f0Sjeremylt                           CeedInt ndof, CeedInt nqpts,
228a8de75f0Sjeremylt                           const CeedScalar *interp,
229a8de75f0Sjeremylt                           const CeedScalar *grad,
230a8de75f0Sjeremylt                           const CeedScalar *qref,
231a8de75f0Sjeremylt                           const CeedScalar *qweight,
232a8de75f0Sjeremylt                           CeedBasis basis) {
233*fe2413ffSjeremylt   int ierr;
234*fe2413ffSjeremylt   Ceed ceed;
235*fe2413ffSjeremylt   ierr = CeedBasisGetCeed(basis, &ceed); CeedChk(ierr);
236*fe2413ffSjeremylt 
237*fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Apply",
238*fe2413ffSjeremylt                                 CeedBasisApply_Ref); CeedChk(ierr);
239*fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Destroy",
240*fe2413ffSjeremylt                                 CeedBasisDestroy_Ref); CeedChk(ierr);
241a8de75f0Sjeremylt   return 0;
242a8de75f0Sjeremylt }
243