xref: /libCEED/backends/ref/ceed-ref-basis.c (revision c042f62f62e10e1321eb699b116e67a6568d5716)
1 // Copyright (c) 2017-2018, Lawrence Livermore National Security, LLC.
2 // Produced at the Lawrence Livermore National Laboratory. LLNL-CODE-734707.
3 // All Rights reserved. See files LICENSE and NOTICE for details.
4 //
5 // This file is part of CEED, a collection of benchmarks, miniapps, software
6 // libraries and APIs for efficient high-order finite element and spectral
7 // element discretizations for exascale applications. For more information and
8 // source code availability see http://github.com/ceed.
9 //
10 // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
11 // a collaborative effort of two U.S. Department of Energy organizations (Office
12 // of Science and the National Nuclear Security Administration) responsible for
13 // the planning and preparation of a capable exascale ecosystem, including
14 // software, applications, hardware, advanced system engineering and early
15 // testbed platforms, in support of the nation's exascale computing imperative.
16 
17 #include "ceed-ref.h"
18 
19 static int CeedBasisApply_Ref(CeedBasis basis, CeedInt nelem,
20                               CeedTransposeMode tmode, CeedEvalMode emode,
21                               CeedVector U, CeedVector V) {
22   int ierr;
23   Ceed ceed;
24   ierr = CeedBasisGetCeed(basis, &ceed); CeedChk(ierr);
25   CeedInt dim, ncomp, nnodes, nqpt;
26   ierr = CeedBasisGetDimension(basis, &dim); CeedChk(ierr);
27   ierr = CeedBasisGetNumComponents(basis, &ncomp); CeedChk(ierr);
28   ierr = CeedBasisGetNumNodes(basis, &nnodes); CeedChk(ierr);
29   ierr = CeedBasisGetNumQuadraturePoints(basis, &nqpt); CeedChk(ierr);
30   CeedTensorContract contract;
31   ierr = CeedBasisGetTensorContract(basis, &contract); CeedChk(ierr);
32   const CeedInt add = (tmode == CEED_TRANSPOSE);
33   const CeedScalar *u;
34   CeedScalar *v;
35   if (U) {
36     ierr = CeedVectorGetArrayRead(U, CEED_MEM_HOST, &u); CeedChk(ierr);
37   } else if (emode != CEED_EVAL_WEIGHT) {
38     // LCOV_EXCL_START
39     return CeedError(ceed, 1,
40                      "An input vector is required for this CeedEvalMode");
41     // LCOV_EXCL_STOP
42   }
43   ierr = CeedVectorGetArray(V, CEED_MEM_HOST, &v); CeedChk(ierr);
44 
45   // Clear v if operating in transpose
46   if (tmode == CEED_TRANSPOSE) {
47     const CeedInt vsize = nelem*ncomp*nnodes;
48     for (CeedInt i = 0; i < vsize; i++)
49       v[i] = (CeedScalar) 0.0;
50   }
51   bool tensorbasis;
52   ierr = CeedBasisGetTensorStatus(basis, &tensorbasis); CeedChk(ierr);
53   // Tensor basis
54   if (tensorbasis) {
55     CeedInt P1d, Q1d;
56     ierr = CeedBasisGetNumNodes1D(basis, &P1d); CeedChk(ierr);
57     ierr = CeedBasisGetNumQuadraturePoints1D(basis, &Q1d); CeedChk(ierr);
58     switch (emode) {
59     // Interpolate to/from quadrature points
60     case CEED_EVAL_INTERP: {
61       CeedBasis_Ref *impl;
62       ierr = CeedBasisGetData(basis, (void *)&impl); CeedChk(ierr);
63       if (impl->collointerp) {
64         memcpy(v, u, nelem*ncomp*nnodes*sizeof(u[0]));
65       } else {
66         CeedInt P = P1d, Q = Q1d;
67         if (tmode == CEED_TRANSPOSE) {
68           P = Q1d; Q = P1d;
69         }
70         CeedInt pre = ncomp*CeedIntPow(P, dim-1), post = nelem;
71         CeedScalar tmp[2][nelem*ncomp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
72         CeedScalar *interp1d;
73         ierr = CeedBasisGetInterp(basis, &interp1d); CeedChk(ierr);
74         for (CeedInt d=0; d<dim; d++) {
75           ierr = CeedTensorContractApply(contract, pre, P, post, Q,
76                                          interp1d, tmode, add&&(d==dim-1),
77                                          d==0?u:tmp[d%2],
78                                          d==dim-1?v:tmp[(d+1)%2]);
79           CeedChk(ierr);
80           pre /= P;
81           post *= Q;
82         }
83       }
84     } break;
85     // Evaluate the gradient to/from quadrature points
86     case CEED_EVAL_GRAD: {
87       // In CEED_NOTRANSPOSE mode:
88       // u has shape [dim, ncomp, P^dim, nelem], row-major layout
89       // v has shape [dim, ncomp, Q^dim, nelem], row-major layout
90       // In CEED_TRANSPOSE mode, the sizes of u and v are switched.
91       CeedInt P = P1d, Q = Q1d;
92       if (tmode == CEED_TRANSPOSE) {
93         P = Q1d, Q = Q1d;
94       }
95       CeedBasis_Ref *impl;
96       ierr = CeedBasisGetData(basis, (void *)&impl); CeedChk(ierr);
97       CeedInt pre = ncomp*CeedIntPow(P, dim-1), post = nelem;
98       CeedScalar *interp1d;
99       ierr = CeedBasisGetInterp(basis, &interp1d); CeedChk(ierr);
100       if (impl->collograd1d) {
101         CeedScalar tmp[2][nelem*ncomp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
102         CeedScalar interp[nelem*ncomp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
103         // Interpolate to quadrature points (NoTranspose)
104         //  or Grad to quadrature points (Transpose)
105         for (CeedInt d=0; d<dim; d++) {
106           ierr = CeedTensorContractApply(contract, pre, P, post, Q,
107                                          (tmode == CEED_NOTRANSPOSE
108                                           ? interp1d
109                                           : impl->collograd1d),
110                                          tmode, add&&(d>0),
111                                          (tmode == CEED_NOTRANSPOSE
112                                           ? (d==0?u:tmp[d%2])
113                                           : u + d*nqpt*ncomp*nelem),
114                                          (tmode == CEED_NOTRANSPOSE
115                                           ? (d==dim-1?interp:tmp[(d+1)%2])
116                                           : interp));
117           CeedChk(ierr);
118           pre /= P;
119           post *= Q;
120         }
121         // Grad to quadrature points (NoTranspose)
122         //  or Interpolate to nodes (Transpose)
123         P = Q1d, Q = Q1d;
124         if (tmode == CEED_TRANSPOSE) {
125           P = Q1d, Q = P1d;
126         }
127         pre = ncomp*CeedIntPow(P, dim-1), post = nelem;
128         for (CeedInt d=0; d<dim; d++) {
129           ierr = CeedTensorContractApply(contract, pre, P, post, Q,
130                                          (tmode == CEED_NOTRANSPOSE
131                                           ? impl->collograd1d
132                                           : interp1d),
133                                          tmode, add&&(d==dim-1),
134                                          (tmode == CEED_NOTRANSPOSE
135                                           ? interp
136                                           : (d==0?interp:tmp[d%2])),
137                                          (tmode == CEED_NOTRANSPOSE
138                                           ? v + d*nqpt*ncomp*nelem
139                                           : (d==dim-1?v:tmp[(d+1)%2])));
140           CeedChk(ierr);
141           pre /= P;
142           post *= Q;
143         }
144       } else if (impl->collointerp) { // Qpts collocated with nodes
145         CeedScalar *grad1d;
146         ierr = CeedBasisGetGrad(basis, &grad1d); CeedChk(ierr);
147 
148         // Dim contractions, identity in other directions
149         for (CeedInt d=0; d<dim; d++) {
150           CeedInt pre = ncomp*CeedIntPow(P, dim-1), post = nelem;
151           ierr = CeedTensorContractApply(contract, pre, P, post, Q,
152                                          grad1d, tmode, add&&(d>0),
153                                          tmode == CEED_NOTRANSPOSE
154                                          ? u : u+d*ncomp*nqpt*nelem,
155                                          tmode == CEED_TRANSPOSE
156                                          ? v : v+d*ncomp*nqpt*nelem);
157           CeedChk(ierr);
158         }
159       } else { // Underintegration, P > Q
160         CeedScalar *grad1d;
161         ierr = CeedBasisGetGrad(basis, &grad1d); CeedChk(ierr);
162 
163         if (tmode == CEED_TRANSPOSE) {
164           P = Q1d, Q = P1d;
165         }
166         CeedScalar tmp[2][nelem*ncomp*Q*CeedIntPow(P>Q?P:Q, dim-1)];
167 
168         // Dim**2 contractions, apply grad when pass == dim
169         for (CeedInt p=0; p<dim; p++) {
170           CeedInt pre = ncomp*CeedIntPow(P, dim-1), post = nelem;
171           for (CeedInt d=0; d<dim; d++) {
172             ierr = CeedTensorContractApply(contract, pre, P, post, Q,
173                                            (p==d)? grad1d : interp1d,
174                                            tmode, add&&(d==dim-1),
175                                            (d == 0
176                                             ? (tmode == CEED_NOTRANSPOSE
177                                                ? u : u+p*ncomp*nqpt*nelem)
178                                             : tmp[d%2]),
179                                            (d == dim-1
180                                             ? (tmode == CEED_TRANSPOSE
181                                                ? v : v+p*ncomp*nqpt*nelem)
182                                             : tmp[(d+1)%2]));
183             CeedChk(ierr);
184             pre /= P;
185             post *= Q;
186           }
187         }
188       }
189     } break;
190     // Retrieve interpolation weights
191     case CEED_EVAL_WEIGHT: {
192       if (tmode == CEED_TRANSPOSE)
193         // LCOV_EXCL_START
194         return CeedError(ceed, 1,
195                          "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE");
196       // LCOV_EXCL_STOP
197       CeedInt Q = Q1d;
198       CeedScalar *qweight1d;
199       ierr = CeedBasisGetQWeights(basis, &qweight1d); CeedChk(ierr);
200       for (CeedInt d=0; d<dim; d++) {
201         CeedInt pre = CeedIntPow(Q, dim-d-1), post = CeedIntPow(Q, d);
202         for (CeedInt i=0; i<pre; i++)
203           for (CeedInt j=0; j<Q; j++)
204             for (CeedInt k=0; k<post; k++) {
205               CeedScalar w = qweight1d[j]
206                              * (d == 0 ? 1 : v[((i*Q + j)*post + k)*nelem]);
207               for (CeedInt e=0; e<nelem; e++)
208                 v[((i*Q + j)*post + k)*nelem + e] = w;
209             }
210       }
211     } break;
212     // LCOV_EXCL_START
213     // Evaluate the divergence to/from the quadrature points
214     case CEED_EVAL_DIV:
215       return CeedError(ceed, 1, "CEED_EVAL_DIV not supported");
216     // Evaluate the curl to/from the quadrature points
217     case CEED_EVAL_CURL:
218       return CeedError(ceed, 1, "CEED_EVAL_CURL not supported");
219     // Take no action, BasisApply should not have been called
220     case CEED_EVAL_NONE:
221       return CeedError(ceed, 1,
222                        "CEED_EVAL_NONE does not make sense in this context");
223     // LCOV_EXCL_STOP
224     }
225   } else {
226     // Non-tensor basis
227     switch (emode) {
228     // Interpolate to/from quadrature points
229     case CEED_EVAL_INTERP: {
230       CeedInt P = nnodes, Q = nqpt;
231       CeedScalar *interp;
232       ierr = CeedBasisGetInterp(basis, &interp); CeedChk(ierr);
233       if (tmode == CEED_TRANSPOSE) {
234         P = nqpt; Q = nnodes;
235       }
236       ierr = CeedTensorContractApply(contract, ncomp, P, nelem, Q,
237                                      interp, tmode, add, u, v);
238       CeedChk(ierr);
239     }
240     break;
241     // Evaluate the gradient to/from quadrature points
242     case CEED_EVAL_GRAD: {
243       CeedInt P = nnodes, Q = dim*nqpt;
244       CeedScalar *grad;
245       ierr = CeedBasisGetGrad(basis, &grad); CeedChk(ierr);
246       if (tmode == CEED_TRANSPOSE) {
247         P = dim*nqpt; Q = nnodes;
248       }
249       ierr = CeedTensorContractApply(contract, ncomp, P, nelem, Q,
250                                      grad, tmode, add, u, v);
251       CeedChk(ierr);
252     }
253     break;
254     // Retrieve interpolation weights
255     case CEED_EVAL_WEIGHT: {
256       if (tmode == CEED_TRANSPOSE)
257         // LCOV_EXCL_START
258         return CeedError(ceed, 1,
259                          "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE");
260       // LCOV_EXCL_STOP
261       CeedScalar *qweight;
262       ierr = CeedBasisGetQWeights(basis, &qweight); CeedChk(ierr);
263       for (CeedInt i=0; i<nqpt; i++)
264         for (CeedInt e=0; e<nelem; e++)
265           v[i*nelem + e] = qweight[i];
266     } break;
267     // LCOV_EXCL_START
268     // Evaluate the divergence to/from the quadrature points
269     case CEED_EVAL_DIV:
270       return CeedError(ceed, 1, "CEED_EVAL_DIV not supported");
271     // Evaluate the curl to/from the quadrature points
272     case CEED_EVAL_CURL:
273       return CeedError(ceed, 1, "CEED_EVAL_CURL not supported");
274     // Take no action, BasisApply should not have been called
275     case CEED_EVAL_NONE:
276       return CeedError(ceed, 1,
277                        "CEED_EVAL_NONE does not make sense in this context");
278     // LCOV_EXCL_STOP
279     }
280   }
281   if (U) {
282     ierr = CeedVectorRestoreArrayRead(U, &u); CeedChk(ierr);
283   }
284   ierr = CeedVectorRestoreArray(V, &v); CeedChk(ierr);
285   return 0;
286 }
287 
288 static int CeedBasisDestroyNonTensor_Ref(CeedBasis basis) {
289   int ierr;
290   CeedTensorContract contract;
291   ierr = CeedBasisGetTensorContract(basis, &contract); CeedChk(ierr);
292   ierr = CeedTensorContractDestroy(&contract); CeedChk(ierr);
293   return 0;
294 }
295 
296 static int CeedBasisDestroyTensor_Ref(CeedBasis basis) {
297   int ierr;
298   CeedTensorContract contract;
299   ierr = CeedBasisGetTensorContract(basis, &contract); CeedChk(ierr);
300   ierr = CeedTensorContractDestroy(&contract); CeedChk(ierr);
301 
302   CeedBasis_Ref *impl;
303   ierr = CeedBasisGetData(basis, (void *)&impl); CeedChk(ierr);
304   ierr = CeedFree(&impl->collograd1d); CeedChk(ierr);
305   ierr = CeedFree(&impl); CeedChk(ierr);
306 
307   return 0;
308 }
309 
310 int CeedBasisCreateTensorH1_Ref(CeedInt dim, CeedInt P1d,
311                                 CeedInt Q1d, const CeedScalar *interp1d,
312                                 const CeedScalar *grad1d,
313                                 const CeedScalar *qref1d,
314                                 const CeedScalar *qweight1d,
315                                 CeedBasis basis) {
316   int ierr;
317   Ceed ceed;
318   ierr = CeedBasisGetCeed(basis, &ceed); CeedChk(ierr);
319   CeedBasis_Ref *impl;
320   ierr = CeedCalloc(1, &impl); CeedChk(ierr);
321   // Check for collocated interp
322   if (Q1d == P1d) {
323     bool collocated = 1;
324     for (CeedInt i=0; i<P1d; i++) {
325       collocated = collocated && (fabs(interp1d[i+P1d*i] - 1.0) < 1e-14);
326       for (CeedInt j=0; j<P1d; j++)
327         if (j != i)
328           collocated = collocated && (fabs(interp1d[j+P1d*i]) < 1e-14);
329     }
330     impl->collointerp = collocated;
331   }
332   // Calculate collocated grad
333   if (Q1d >= P1d && !impl->collointerp) {
334     ierr = CeedMalloc(Q1d*Q1d, &impl->collograd1d); CeedChk(ierr);
335     ierr = CeedBasisGetCollocatedGrad(basis, impl->collograd1d); CeedChk(ierr);
336   }
337   ierr = CeedBasisSetData(basis, (void *)&impl); CeedChk(ierr);
338 
339   Ceed parent;
340   ierr = CeedGetParent(ceed, &parent); CeedChk(ierr);
341   CeedTensorContract contract;
342   ierr = CeedTensorContractCreate(parent, basis, &contract); CeedChk(ierr);
343   ierr = CeedBasisSetTensorContract(basis, &contract); CeedChk(ierr);
344 
345   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Apply",
346                                 CeedBasisApply_Ref); CeedChk(ierr);
347   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Destroy",
348                                 CeedBasisDestroyTensor_Ref); CeedChk(ierr);
349   return 0;
350 }
351 
352 
353 
354 int CeedBasisCreateH1_Ref(CeedElemTopology topo, CeedInt dim,
355                           CeedInt nnodes, CeedInt nqpts,
356                           const CeedScalar *interp,
357                           const CeedScalar *grad,
358                           const CeedScalar *qref,
359                           const CeedScalar *qweight,
360                           CeedBasis basis) {
361   int ierr;
362   Ceed ceed;
363   ierr = CeedBasisGetCeed(basis, &ceed); CeedChk(ierr);
364 
365   Ceed parent;
366   ierr = CeedGetParent(ceed, &parent); CeedChk(ierr);
367   CeedTensorContract contract;
368   ierr = CeedTensorContractCreate(parent, basis, &contract); CeedChk(ierr);
369   ierr = CeedBasisSetTensorContract(basis, &contract); CeedChk(ierr);
370 
371   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Apply",
372                                 CeedBasisApply_Ref); CeedChk(ierr);
373   ierr = CeedSetBackendFunction(ceed, "Basis", basis, "Destroy",
374                                 CeedBasisDestroyNonTensor_Ref); CeedChk(ierr);
375 
376   return 0;
377 }
378