xref: /libCEED/rust/libceed-sys/c-src/backends/ref/ceed-ref-basis.c (revision aedaa0e5fd3a3e03ad33ad8a6308ac527f4f900e)
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 "+="
241dfeef1dSjeremylt static int CeedTensorContract_Ref(Ceed ceed, CeedInt A, CeedInt B, CeedInt C,
251dfeef1dSjeremylt                                   CeedInt J,
2612170c1eSJed Brown                                   const CeedScalar *restrict t, CeedTransposeMode tmode,
2721617c04Sjeremylt                                   const CeedInt Add,
2812170c1eSJed Brown                                   const CeedScalar *restrict u, CeedScalar *restrict v) {
2921617c04Sjeremylt   CeedInt tstride0 = B, tstride1 = 1;
3021617c04Sjeremylt   if (tmode == CEED_TRANSPOSE) {
3121617c04Sjeremylt     tstride0 = 1; tstride1 = J;
3221617c04Sjeremylt   }
3321617c04Sjeremylt 
34a2b73c81Sjeremylt   if (!Add)
35a2b73c81Sjeremylt     for (CeedInt q=0; q<A*J*C; q++)
361c19f432SSteven Roberts       v[q] = (CeedScalar) 0.0;
371c19f432SSteven Roberts 
38a2b73c81Sjeremylt   for (CeedInt a=0; a<A; a++)
39a2b73c81Sjeremylt     for (CeedInt b=0; b<B; b++)
401c19f432SSteven Roberts       for (CeedInt j=0; j<J; j++) {
411c19f432SSteven Roberts         CeedScalar tq = t[j*tstride0 + b*tstride1];
42a2b73c81Sjeremylt         for (CeedInt c=0; c<C; c++)
43282be9a0SSteven Roberts           v[(a*J+j)*C+c] += tq * u[(a*B+b)*C+c];
4421617c04Sjeremylt       }
4521617c04Sjeremylt   return 0;
4621617c04Sjeremylt }
4721617c04Sjeremylt 
48d3181881Sjeremylt static int CeedBasisApply_Ref(CeedBasis basis, CeedInt nelem,
49d3181881Sjeremylt                               CeedTransposeMode tmode, CeedEvalMode emode,
50*aedaa0e5Sjeremylt                               CeedVector U, CeedVector V) {
5121617c04Sjeremylt   int ierr;
524ce2993fSjeremylt   Ceed ceed;
534ce2993fSjeremylt   ierr = CeedBasisGetCeed(basis, &ceed); CeedChk(ierr);
544ce2993fSjeremylt   CeedInt dim, ncomp, ndof, nqpt;
554ce2993fSjeremylt   ierr = CeedBasisGetDimension(basis, &dim); CeedChk(ierr);
564ce2993fSjeremylt   ierr = CeedBasisGetNumComponents(basis, &ncomp); CeedChk(ierr);
57a8de75f0Sjeremylt   ierr = CeedBasisGetNumNodes(basis, &ndof); CeedChk(ierr);
584ce2993fSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis, &nqpt); CeedChk(ierr);
5921617c04Sjeremylt   const CeedInt add = (tmode == CEED_TRANSPOSE);
60*aedaa0e5Sjeremylt   const CeedScalar *u;
61*aedaa0e5Sjeremylt   CeedScalar *v;
62*aedaa0e5Sjeremylt   if (U) {
63*aedaa0e5Sjeremylt     ierr = CeedVectorGetArrayRead(U, CEED_MEM_HOST, &u); CeedChk(ierr);
64*aedaa0e5Sjeremylt   } else if (emode != CEED_EVAL_WEIGHT) {
65*aedaa0e5Sjeremylt       return CeedError(ceed, 1,
66*aedaa0e5Sjeremylt                        "An input vector is required for this CeedEvalMode");
67*aedaa0e5Sjeremylt   }
68*aedaa0e5Sjeremylt   ierr = CeedVectorGetArray(V, CEED_MEM_HOST, &v); CeedChk(ierr);
6921617c04Sjeremylt 
70c44a85f4Sjeremylt   if (nelem != 1)
714ce2993fSjeremylt     return CeedError(ceed, 1,
72c44a85f4Sjeremylt                      "This backend does not support BasisApply for multiple elements");
73c44a85f4Sjeremylt 
748d94b059Sjeremylt   // Clear v if operating in transpose
7521617c04Sjeremylt   if (tmode == CEED_TRANSPOSE) {
76a8de75f0Sjeremylt     const CeedInt vsize = ncomp*ndof;
7721617c04Sjeremylt     for (CeedInt i = 0; i < vsize; i++)
7821617c04Sjeremylt       v[i] = (CeedScalar) 0;
7921617c04Sjeremylt   }
80a8de75f0Sjeremylt   // Tensor basis
814ce2993fSjeremylt   bool tensorbasis;
824ce2993fSjeremylt   ierr = CeedBasisGetTensorStatus(basis, &tensorbasis); CeedChk(ierr);
834ce2993fSjeremylt   if (tensorbasis) {
844ce2993fSjeremylt     CeedInt P1d, Q1d;
854ce2993fSjeremylt     ierr = CeedBasisGetNumNodes1D(basis, &P1d); CeedChk(ierr);
864ce2993fSjeremylt     ierr = CeedBasisGetNumQuadraturePoints1D(basis, &Q1d); CeedChk(ierr);
87a2b73c81Sjeremylt     switch (emode) {
888d94b059Sjeremylt     // Interpolate to/from quadrature points
89a2b73c81Sjeremylt     case CEED_EVAL_INTERP: {
904ce2993fSjeremylt       CeedInt P = P1d, Q = Q1d;
9121617c04Sjeremylt       if (tmode == CEED_TRANSPOSE) {
924ce2993fSjeremylt         P = Q1d; Q = P1d;
9321617c04Sjeremylt       }
94b5cf12eeSjeremylt       CeedInt pre = ncomp*CeedIntPow(P, dim-1), post = 1;
95b5cf12eeSjeremylt       CeedScalar tmp[2][ncomp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
964ce2993fSjeremylt       CeedScalar *interp1d;
974ce2993fSjeremylt       ierr = CeedBasisGetInterp(basis, &interp1d); CeedChk(ierr);
9821617c04Sjeremylt       for (CeedInt d=0; d<dim; d++) {
994ce2993fSjeremylt         ierr = CeedTensorContract_Ref(ceed, pre, P, post, Q, interp1d,
10021617c04Sjeremylt                                       tmode, add&&(d==dim-1),
10121617c04Sjeremylt                                       d==0?u:tmp[d%2], d==dim-1?v:tmp[(d+1)%2]);
10221617c04Sjeremylt         CeedChk(ierr);
10321617c04Sjeremylt         pre /= P;
10421617c04Sjeremylt         post *= Q;
10521617c04Sjeremylt       }
106a2b73c81Sjeremylt     } break;
1078d94b059Sjeremylt     // Evaluate the gradient to/from quadrature points
108a2b73c81Sjeremylt     case CEED_EVAL_GRAD: {
1094ce2993fSjeremylt       CeedInt P = P1d, Q = Q1d;
11021617c04Sjeremylt       // In CEED_NOTRANSPOSE mode:
111ecf6354eSJed Brown       // u has shape [dim, ncomp, P^dim, nelem], row-major layout
112ecf6354eSJed Brown       // v has shape [dim, ncomp, Q^dim, nelem], row-major layout
11321617c04Sjeremylt       // In CEED_TRANSPOSE mode, the sizes of u and v are switched.
11421617c04Sjeremylt       if (tmode == CEED_TRANSPOSE) {
1154ce2993fSjeremylt         P = Q1d, Q = P1d;
11621617c04Sjeremylt       }
117b5cf12eeSjeremylt       CeedScalar tmp[2][ncomp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
1184ce2993fSjeremylt       CeedScalar *interp1d, *grad1d;
1194ce2993fSjeremylt       ierr = CeedBasisGetInterp(basis, &interp1d); CeedChk(ierr);
1204ce2993fSjeremylt       ierr = CeedBasisGetGrad(basis, &grad1d); CeedChk(ierr);
12121617c04Sjeremylt       for (CeedInt p = 0; p < dim; p++) {
122b5cf12eeSjeremylt         CeedInt pre = ncomp*CeedIntPow(P, dim-1), post = 1;
12321617c04Sjeremylt         for (CeedInt d=0; d<dim; d++) {
1244ce2993fSjeremylt           ierr = CeedTensorContract_Ref(ceed, pre, P, post, Q,
1254ce2993fSjeremylt                                         (p==d)?grad1d:interp1d,
12621617c04Sjeremylt                                         tmode, add&&(d==dim-1),
1274b8bea3bSJed Brown                                         (d == 0
128a2b73c81Sjeremylt                                          ? (tmode==CEED_NOTRANSPOSE?u:u+p*ncomp*nqpt)
1294b8bea3bSJed Brown                                          : tmp[d%2]),
1304b8bea3bSJed Brown                                         (d == dim-1
131a2b73c81Sjeremylt                                          ? (tmode==CEED_TRANSPOSE?v:v+p*ncomp*nqpt)
1324b8bea3bSJed Brown                                          : tmp[(d+1)%2]));
13321617c04Sjeremylt           CeedChk(ierr);
13421617c04Sjeremylt           pre /= P;
13521617c04Sjeremylt           post *= Q;
13621617c04Sjeremylt         }
13721617c04Sjeremylt       }
138a2b73c81Sjeremylt     } break;
1398d94b059Sjeremylt     // Retrieve interpolation weights
140a2b73c81Sjeremylt     case CEED_EVAL_WEIGHT: {
14121617c04Sjeremylt       if (tmode == CEED_TRANSPOSE)
1424ce2993fSjeremylt         return CeedError(ceed, 1,
14321617c04Sjeremylt                          "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE");
1444ce2993fSjeremylt       CeedInt Q = Q1d;
1454ce2993fSjeremylt       CeedScalar *qweight1d;
1464ce2993fSjeremylt       ierr = CeedBasisGetQWeights(basis, &qweight1d); CeedChk(ierr);
14721617c04Sjeremylt       for (CeedInt d=0; d<dim; d++) {
148b5cf12eeSjeremylt         CeedInt pre = CeedIntPow(Q, dim-d-1), post = CeedIntPow(Q, d);
149a2b73c81Sjeremylt         for (CeedInt i=0; i<pre; i++)
150a2b73c81Sjeremylt           for (CeedInt j=0; j<Q; j++)
151a2b73c81Sjeremylt             for (CeedInt k=0; k<post; k++)
1524ce2993fSjeremylt               v[(i*Q + j)*post + k] = qweight1d[j]
15321617c04Sjeremylt                                       * (d == 0 ? 1 : v[(i*Q + j)*post + k]);
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) {
170a8de75f0Sjeremylt     case CEED_EVAL_INTERP: {
1714ce2993fSjeremylt       CeedInt P = ndof, Q = nqpt;
1724ce2993fSjeremylt       CeedScalar *interp;
1734ce2993fSjeremylt       ierr = CeedBasisGetInterp(basis, &interp); CeedChk(ierr);
174a8de75f0Sjeremylt       if (tmode == CEED_TRANSPOSE) {
1754ce2993fSjeremylt         P = nqpt; Q = ndof;
176a8de75f0Sjeremylt       }
1774ce2993fSjeremylt       ierr = CeedTensorContract_Ref(ceed, ncomp, P, 1, Q, interp,
178a8de75f0Sjeremylt                                     tmode, add, u, v);
179a8de75f0Sjeremylt       CeedChk(ierr);
180a8de75f0Sjeremylt     }
181a8de75f0Sjeremylt     break;
182a8de75f0Sjeremylt     case CEED_EVAL_GRAD: {
1834ce2993fSjeremylt       CeedInt P = ndof, Q = dim*nqpt;
1844ce2993fSjeremylt       CeedScalar *grad;
1854ce2993fSjeremylt       ierr = CeedBasisGetGrad(basis, &grad); CeedChk(ierr);
186a8de75f0Sjeremylt       if (tmode == CEED_TRANSPOSE) {
1874ce2993fSjeremylt         P = dim*nqpt; Q = ndof;
188a8de75f0Sjeremylt       }
1894ce2993fSjeremylt       ierr = CeedTensorContract_Ref(ceed, ncomp, P, 1, Q, grad,
190a8de75f0Sjeremylt                                     tmode, add, u, v);
191a8de75f0Sjeremylt       CeedChk(ierr);
192a8de75f0Sjeremylt     }
193a8de75f0Sjeremylt     break;
194a8de75f0Sjeremylt     case CEED_EVAL_WEIGHT: {
195a8de75f0Sjeremylt       if (tmode == CEED_TRANSPOSE)
1964ce2993fSjeremylt         return CeedError(ceed, 1,
197a8de75f0Sjeremylt                          "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE");
1984ce2993fSjeremylt       CeedScalar *qweight;
1994ce2993fSjeremylt       ierr = CeedBasisGetQWeights(basis, &qweight); CeedChk(ierr);
200a8de75f0Sjeremylt       for (CeedInt i=0; i<nqpt; i++)
2014ce2993fSjeremylt         v[i] = qweight[i];
202a8de75f0Sjeremylt     } break;
203a8de75f0Sjeremylt     case CEED_EVAL_DIV:
2044ce2993fSjeremylt       return CeedError(ceed, 1, "CEED_EVAL_DIV not supported");
205a8de75f0Sjeremylt     case CEED_EVAL_CURL:
2064ce2993fSjeremylt       return CeedError(ceed, 1, "CEED_EVAL_CURL not supported");
207a8de75f0Sjeremylt     case CEED_EVAL_NONE:
2084ce2993fSjeremylt       return CeedError(ceed, 1,
209a8de75f0Sjeremylt                        "CEED_EVAL_NONE does not make sense in this context");
210a8de75f0Sjeremylt     }
211a8de75f0Sjeremylt   }
212*aedaa0e5Sjeremylt   if (U) {
213*aedaa0e5Sjeremylt     ierr = CeedVectorRestoreArrayRead(U, &u); CeedChk(ierr);
214*aedaa0e5Sjeremylt   }
215*aedaa0e5Sjeremylt   ierr = CeedVectorRestoreArray(V, &v); CeedChk(ierr);
21621617c04Sjeremylt   return 0;
21721617c04Sjeremylt }
21821617c04Sjeremylt 
21921617c04Sjeremylt static int CeedBasisDestroy_Ref(CeedBasis basis) {
22021617c04Sjeremylt   return 0;
22121617c04Sjeremylt }
22221617c04Sjeremylt 
223667bc5fcSjeremylt int CeedBasisCreateTensorH1_Ref(CeedInt dim, CeedInt P1d,
22421617c04Sjeremylt                                 CeedInt Q1d, const CeedScalar *interp1d,
22521617c04Sjeremylt                                 const CeedScalar *grad1d,
22621617c04Sjeremylt                                 const CeedScalar *qref1d,
22721617c04Sjeremylt                                 const CeedScalar *qweight1d,
22821617c04Sjeremylt                                 CeedBasis basis) {
229fe2413ffSjeremylt   int ierr;
230fe2413ffSjeremylt   Ceed ceed;
231fe2413ffSjeremylt   ierr = CeedBasisGetCeed(basis, &ceed); CeedChk(ierr);
232fe2413ffSjeremylt 
233fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Apply",
234fe2413ffSjeremylt                                 CeedBasisApply_Ref); CeedChk(ierr);
235fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Destroy",
236fe2413ffSjeremylt                                 CeedBasisDestroy_Ref); CeedChk(ierr);
23721617c04Sjeremylt   return 0;
23821617c04Sjeremylt }
239a8de75f0Sjeremylt 
240667bc5fcSjeremylt int CeedBasisCreateH1_Ref(CeedElemTopology topo, CeedInt dim,
241a8de75f0Sjeremylt                           CeedInt ndof, CeedInt nqpts,
242a8de75f0Sjeremylt                           const CeedScalar *interp,
243a8de75f0Sjeremylt                           const CeedScalar *grad,
244a8de75f0Sjeremylt                           const CeedScalar *qref,
245a8de75f0Sjeremylt                           const CeedScalar *qweight,
246a8de75f0Sjeremylt                           CeedBasis basis) {
247fe2413ffSjeremylt   int ierr;
248fe2413ffSjeremylt   Ceed ceed;
249fe2413ffSjeremylt   ierr = CeedBasisGetCeed(basis, &ceed); CeedChk(ierr);
250fe2413ffSjeremylt 
251fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Apply",
252fe2413ffSjeremylt                                 CeedBasisApply_Ref); CeedChk(ierr);
253fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Destroy",
254fe2413ffSjeremylt                                 CeedBasisDestroy_Ref); CeedChk(ierr);
255a8de75f0Sjeremylt   return 0;
256a8de75f0Sjeremylt }
257