xref: /libCEED/rust/libceed-sys/c-src/backends/ref/ceed-ref-basis.c (revision 667bc5fc645d14cb3c263707ff57e9bb45c3befc)
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-impl.h>
1821617c04Sjeremylt #include <string.h>
1921617c04Sjeremylt #include "ceed-ref.h"
2021617c04Sjeremylt 
2121617c04Sjeremylt // Contracts on the middle index
2221617c04Sjeremylt // NOTRANSPOSE: V_ajc = T_jb U_abc
2321617c04Sjeremylt // TRANSPOSE:   V_ajc = T_bj U_abc
2421617c04Sjeremylt // If Add != 0, "=" is replaced by "+="
25*667bc5fcSjeremylt static int CeedTensorContract_Ref(CeedInt A, CeedInt B, CeedInt C, 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,
5021617c04Sjeremylt                               const CeedScalar *u, CeedScalar *v) {
5121617c04Sjeremylt   int ierr;
5221617c04Sjeremylt   const CeedInt dim = basis->dim;
530f5de9e9Sjeremylt   const CeedInt ncomp = basis->ncomp;
54a8de75f0Sjeremylt   CeedInt nqpt;
55a8de75f0Sjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis, &nqpt); CeedChk(ierr);
56a8de75f0Sjeremylt   CeedInt ndof;
57a8de75f0Sjeremylt   ierr = CeedBasisGetNumNodes(basis, &ndof); CeedChk(ierr);
5821617c04Sjeremylt   const CeedInt add = (tmode == CEED_TRANSPOSE);
5921617c04Sjeremylt 
60c44a85f4Sjeremylt   if (nelem != 1)
61c44a85f4Sjeremylt     return CeedError(basis->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
71a8de75f0Sjeremylt   if (basis->tensorbasis) {
72a2b73c81Sjeremylt     switch (emode) {
738d94b059Sjeremylt     // Interpolate to/from quadrature points
74a2b73c81Sjeremylt     case CEED_EVAL_INTERP: {
7521617c04Sjeremylt       CeedInt P = basis->P1d, Q = basis->Q1d;
7621617c04Sjeremylt       if (tmode == CEED_TRANSPOSE) {
7721617c04Sjeremylt         P = basis->Q1d; Q = basis->P1d;
7821617c04Sjeremylt       }
79b5cf12eeSjeremylt       CeedInt pre = ncomp*CeedIntPow(P, dim-1), post = 1;
80b5cf12eeSjeremylt       CeedScalar tmp[2][ncomp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
8121617c04Sjeremylt       for (CeedInt d=0; d<dim; d++) {
82*667bc5fcSjeremylt         ierr = CeedTensorContract_Ref(pre, P, post, Q, basis->interp1d,
8321617c04Sjeremylt                                       tmode, add&&(d==dim-1),
8421617c04Sjeremylt                                       d==0?u:tmp[d%2], d==dim-1?v:tmp[(d+1)%2]);
8521617c04Sjeremylt         CeedChk(ierr);
8621617c04Sjeremylt         pre /= P;
8721617c04Sjeremylt         post *= Q;
8821617c04Sjeremylt       }
89a2b73c81Sjeremylt     } break;
908d94b059Sjeremylt     // Evaluate the gradient to/from quadrature points
91a2b73c81Sjeremylt     case CEED_EVAL_GRAD: {
9221617c04Sjeremylt       CeedInt P = basis->P1d, Q = basis->Q1d;
9321617c04Sjeremylt       // In CEED_NOTRANSPOSE mode:
94ecf6354eSJed Brown       // u has shape [dim, ncomp, P^dim, nelem], row-major layout
95ecf6354eSJed Brown       // v has shape [dim, ncomp, Q^dim, nelem], row-major layout
9621617c04Sjeremylt       // In CEED_TRANSPOSE mode, the sizes of u and v are switched.
9721617c04Sjeremylt       if (tmode == CEED_TRANSPOSE) {
9821617c04Sjeremylt         P = basis->Q1d, Q = basis->P1d;
9921617c04Sjeremylt       }
100b5cf12eeSjeremylt       CeedScalar tmp[2][ncomp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
10121617c04Sjeremylt       for (CeedInt p = 0; p < dim; p++) {
102b5cf12eeSjeremylt         CeedInt pre = ncomp*CeedIntPow(P, dim-1), post = 1;
10321617c04Sjeremylt         for (CeedInt d=0; d<dim; d++) {
104*667bc5fcSjeremylt           ierr = CeedTensorContract_Ref(pre, P, post, Q,
10521617c04Sjeremylt                                         (p==d)?basis->grad1d:basis->interp1d,
10621617c04Sjeremylt                                         tmode, add&&(d==dim-1),
1074b8bea3bSJed Brown                                         (d == 0
108a2b73c81Sjeremylt                                          ? (tmode==CEED_NOTRANSPOSE?u:u+p*ncomp*nqpt)
1094b8bea3bSJed Brown                                          : tmp[d%2]),
1104b8bea3bSJed Brown                                         (d == dim-1
111a2b73c81Sjeremylt                                          ? (tmode==CEED_TRANSPOSE?v:v+p*ncomp*nqpt)
1124b8bea3bSJed Brown                                          : tmp[(d+1)%2]));
11321617c04Sjeremylt           CeedChk(ierr);
11421617c04Sjeremylt           pre /= P;
11521617c04Sjeremylt           post *= Q;
11621617c04Sjeremylt         }
11721617c04Sjeremylt       }
118a2b73c81Sjeremylt     } break;
1198d94b059Sjeremylt     // Retrieve interpolation weights
120a2b73c81Sjeremylt     case CEED_EVAL_WEIGHT: {
12121617c04Sjeremylt       if (tmode == CEED_TRANSPOSE)
12221617c04Sjeremylt         return CeedError(basis->ceed, 1,
12321617c04Sjeremylt                          "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE");
12421617c04Sjeremylt       CeedInt Q = basis->Q1d;
12521617c04Sjeremylt       for (CeedInt d=0; d<dim; d++) {
126b5cf12eeSjeremylt         CeedInt pre = CeedIntPow(Q, dim-d-1), post = CeedIntPow(Q, d);
127a2b73c81Sjeremylt         for (CeedInt i=0; i<pre; i++)
128a2b73c81Sjeremylt           for (CeedInt j=0; j<Q; j++)
129a2b73c81Sjeremylt             for (CeedInt k=0; k<post; k++)
13021617c04Sjeremylt               v[(i*Q + j)*post + k] = basis->qweight1d[j]
13121617c04Sjeremylt                                       * (d == 0 ? 1 : v[(i*Q + j)*post + k]);
13221617c04Sjeremylt       }
133a2b73c81Sjeremylt     } break;
1348d94b059Sjeremylt     // Evaluate the divergence to/from the quadrature points
135a2b73c81Sjeremylt     case CEED_EVAL_DIV:
136a2b73c81Sjeremylt       return CeedError(basis->ceed, 1, "CEED_EVAL_DIV not supported");
1378d94b059Sjeremylt     // Evaluate the curl to/from the quadrature points
138a2b73c81Sjeremylt     case CEED_EVAL_CURL:
139a2b73c81Sjeremylt       return CeedError(basis->ceed, 1, "CEED_EVAL_CURL not supported");
1408d94b059Sjeremylt     // Take no action, BasisApply should not have been called
141a2b73c81Sjeremylt     case CEED_EVAL_NONE:
1424b8bea3bSJed Brown       return CeedError(basis->ceed, 1,
1434b8bea3bSJed Brown                        "CEED_EVAL_NONE does not make sense in this context");
14421617c04Sjeremylt     }
145a8de75f0Sjeremylt   } else {
146a8de75f0Sjeremylt     // Non-tensor basis
147a8de75f0Sjeremylt     switch (emode) {
148a8de75f0Sjeremylt     case CEED_EVAL_INTERP: {
149a8de75f0Sjeremylt       CeedInt P = basis->P, Q = basis->Q;
150a8de75f0Sjeremylt       if (tmode == CEED_TRANSPOSE) {
151a8de75f0Sjeremylt         P = basis->Q; Q = basis->P;
152a8de75f0Sjeremylt       }
153*667bc5fcSjeremylt       ierr = CeedTensorContract_Ref(ncomp, P, 1, Q, basis->interp1d,
154a8de75f0Sjeremylt                                     tmode, add, u, v);
155a8de75f0Sjeremylt       CeedChk(ierr);
156a8de75f0Sjeremylt     }
157a8de75f0Sjeremylt     break;
158a8de75f0Sjeremylt     case CEED_EVAL_GRAD: {
159a8de75f0Sjeremylt       CeedInt P = basis->P, Q = dim*basis->Q;
160a8de75f0Sjeremylt       if (tmode == CEED_TRANSPOSE) {
161a8de75f0Sjeremylt         P = dim*basis->Q; Q = basis->P;
162a8de75f0Sjeremylt       }
163*667bc5fcSjeremylt       ierr = CeedTensorContract_Ref(ncomp, P, 1, Q, basis->grad1d,
164a8de75f0Sjeremylt                                     tmode, add, u, v);
165a8de75f0Sjeremylt       CeedChk(ierr);
166a8de75f0Sjeremylt     }
167a8de75f0Sjeremylt     break;
168a8de75f0Sjeremylt     case CEED_EVAL_WEIGHT: {
169a8de75f0Sjeremylt       if (tmode == CEED_TRANSPOSE)
170a8de75f0Sjeremylt         return CeedError(basis->ceed, 1,
171a8de75f0Sjeremylt                          "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE");
172a8de75f0Sjeremylt       for (CeedInt i=0; i<nqpt; i++)
173a8de75f0Sjeremylt         v[i] = basis->qweight1d[i];
174a8de75f0Sjeremylt     } break;
175a8de75f0Sjeremylt     case CEED_EVAL_DIV:
176a8de75f0Sjeremylt       return CeedError(basis->ceed, 1, "CEED_EVAL_DIV not supported");
177a8de75f0Sjeremylt     case CEED_EVAL_CURL:
178a8de75f0Sjeremylt       return CeedError(basis->ceed, 1, "CEED_EVAL_CURL not supported");
179a8de75f0Sjeremylt     case CEED_EVAL_NONE:
180a8de75f0Sjeremylt       return CeedError(basis->ceed, 1,
181a8de75f0Sjeremylt                        "CEED_EVAL_NONE does not make sense in this context");
182a8de75f0Sjeremylt     }
183a8de75f0Sjeremylt   }
18421617c04Sjeremylt   return 0;
18521617c04Sjeremylt }
18621617c04Sjeremylt 
18721617c04Sjeremylt static int CeedBasisDestroy_Ref(CeedBasis basis) {
18821617c04Sjeremylt   return 0;
18921617c04Sjeremylt }
19021617c04Sjeremylt 
191*667bc5fcSjeremylt int CeedBasisCreateTensorH1_Ref(CeedInt dim, CeedInt P1d,
19221617c04Sjeremylt                                 CeedInt Q1d, const CeedScalar *interp1d,
19321617c04Sjeremylt                                 const CeedScalar *grad1d,
19421617c04Sjeremylt                                 const CeedScalar *qref1d,
19521617c04Sjeremylt                                 const CeedScalar *qweight1d,
19621617c04Sjeremylt                                 CeedBasis basis) {
19721617c04Sjeremylt   basis->Apply = CeedBasisApply_Ref;
19821617c04Sjeremylt   basis->Destroy = CeedBasisDestroy_Ref;
19921617c04Sjeremylt   return 0;
20021617c04Sjeremylt }
201a8de75f0Sjeremylt 
202*667bc5fcSjeremylt int CeedBasisCreateH1_Ref(CeedElemTopology topo, CeedInt dim,
203a8de75f0Sjeremylt                           CeedInt ndof, CeedInt nqpts,
204a8de75f0Sjeremylt                           const CeedScalar *interp,
205a8de75f0Sjeremylt                           const CeedScalar *grad,
206a8de75f0Sjeremylt                           const CeedScalar *qref,
207a8de75f0Sjeremylt                           const CeedScalar *qweight,
208a8de75f0Sjeremylt                           CeedBasis basis) {
209a8de75f0Sjeremylt   basis->Apply = CeedBasisApply_Ref;
210a8de75f0Sjeremylt   basis->Destroy = CeedBasisDestroy_Ref;
211a8de75f0Sjeremylt   return 0;
212a8de75f0Sjeremylt }
213