xref: /libCEED/interface/ceed-qfunction.c (revision b11c1e72297b0dbe2250cea5be89aa8490095155)
1d7b241e6Sjeremylt // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at
2d7b241e6Sjeremylt // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
3d7b241e6Sjeremylt // reserved. See files LICENSE and NOTICE for details.
4d7b241e6Sjeremylt //
5d7b241e6Sjeremylt // This file is part of CEED, a collection of benchmarks, miniapps, software
6d7b241e6Sjeremylt // libraries and APIs for efficient high-order finite element and spectral
7d7b241e6Sjeremylt // element discretizations for exascale applications. For more information and
8d7b241e6Sjeremylt // source code availability see http://github.com/ceed.
9d7b241e6Sjeremylt //
10d7b241e6Sjeremylt // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
11d7b241e6Sjeremylt // a collaborative effort of two U.S. Department of Energy organizations (Office
12d7b241e6Sjeremylt // of Science and the National Nuclear Security Administration) responsible for
13d7b241e6Sjeremylt // the planning and preparation of a capable exascale ecosystem, including
14d7b241e6Sjeremylt // software, applications, hardware, advanced system engineering and early
15d7b241e6Sjeremylt // testbed platforms, in support of the nation's exascale computing imperative.
16d7b241e6Sjeremylt 
17d7b241e6Sjeremylt #include <ceed-impl.h>
18d7b241e6Sjeremylt #include <string.h>
19d7b241e6Sjeremylt 
20d7b241e6Sjeremylt /**
21d7b241e6Sjeremylt   @file
22d7b241e6Sjeremylt   Implementation of public CeedQFunction interfaces
23d7b241e6Sjeremylt 
24d7b241e6Sjeremylt   @defgroup CeedQFunction CeedQFunction: independent operations at quadrature points
25d7b241e6Sjeremylt   @{
26d7b241e6Sjeremylt  */
27d7b241e6Sjeremylt 
28d7b241e6Sjeremylt /**
29d7b241e6Sjeremylt   @brief Create a CeedQFunction for evaluating interior (volumetric) terms.
30d7b241e6Sjeremylt 
31*b11c1e72Sjeremylt   @param ceed       A Ceed object where the CeedQFunction will be created
32d7b241e6Sjeremylt   @param vlength    Vector length.  Caller must ensure that number of quadrature
33d7b241e6Sjeremylt                     points is a multiple of vlength.
34d7b241e6Sjeremylt   @param f          Function pointer to evaluate action at quadrature points.
35d7b241e6Sjeremylt                     See below.
36d7b241e6Sjeremylt   @param focca      OCCA identifier "file.c:function_name" for definition of `f`
37*b11c1e72Sjeremylt   @param[out] qf    Address of the variable where the newly created
38*b11c1e72Sjeremylt                      CeedQFunction will be stored
39*b11c1e72Sjeremylt 
40*b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
41d7b241e6Sjeremylt 
42d7b241e6Sjeremylt   The arguments of the call-back 'function' are:
43d7b241e6Sjeremylt 
44d7b241e6Sjeremylt    1. [void *ctx][in/out] - user data, this is the 'ctx' pointer stored in
45d7b241e6Sjeremylt               the CeedQFunction, set by calling CeedQFunctionSetContext
46d7b241e6Sjeremylt 
47d7b241e6Sjeremylt    2. [CeedInt nq][in] - number of quadrature points to process
48d7b241e6Sjeremylt 
49d7b241e6Sjeremylt    3. [const CeedScalar *const *u][in] - input fields data at quadrature pts, listed in the order given by the user
50d7b241e6Sjeremylt 
51d7b241e6Sjeremylt    4. [CeedScalar *const *v][out] - output fields data at quadrature points, again listed in order given by the user
52d7b241e6Sjeremylt 
53d7b241e6Sjeremylt */
54d7b241e6Sjeremylt int CeedQFunctionCreateInterior(Ceed ceed, CeedInt vlength,
55d7b241e6Sjeremylt                                 int (*f)(void*, CeedInt, const CeedScalar *const*, CeedScalar *const*),
56d7b241e6Sjeremylt                                 const char *focca, CeedQFunction *qf) {
57d7b241e6Sjeremylt   int ierr;
58d7b241e6Sjeremylt   char *focca_copy;
59d7b241e6Sjeremylt 
60d7b241e6Sjeremylt   if (!ceed->QFunctionCreate)
61d7b241e6Sjeremylt     return CeedError(ceed, 1, "Backend does not support QFunctionCreate");
62d7b241e6Sjeremylt   ierr = CeedCalloc(1,qf); CeedChk(ierr);
63d7b241e6Sjeremylt   (*qf)->ceed = ceed;
64d7b241e6Sjeremylt   ceed->refcount++;
65d7b241e6Sjeremylt   (*qf)->refcount = 1;
66d7b241e6Sjeremylt   (*qf)->vlength = vlength;
67d7b241e6Sjeremylt   (*qf)->function = f;
68d7b241e6Sjeremylt   ierr = CeedCalloc(strlen(focca)+1, &focca_copy); CeedChk(ierr);
69d7b241e6Sjeremylt   strcpy(focca_copy, focca);
70d7b241e6Sjeremylt   (*qf)->focca = focca_copy;
71d7b241e6Sjeremylt   ierr = ceed->QFunctionCreate(*qf); CeedChk(ierr);
72d7b241e6Sjeremylt   return 0;
73d7b241e6Sjeremylt }
74d7b241e6Sjeremylt 
75*b11c1e72Sjeremylt /**
76*b11c1e72Sjeremylt   @brief Set a CEEDQFunction field, used by CeedQFunctionAddInput/Output
77*b11c1e72Sjeremylt 
78*b11c1e72Sjeremylt   @param f          CeedQFunctionField
79*b11c1e72Sjeremylt   @param fieldname  Name of QFunction field
80*b11c1e72Sjeremylt   @param ncomp      Number of components per quadrature node
81*b11c1e72Sjeremylt   @param emode      \ref CEED_EVAL_NONE to use values directly,
82*b11c1e72Sjeremylt                       \ref CEED_EVAL_INTERP to use interpolated values,
83*b11c1e72Sjeremylt                       \ref CEED_EVAL_GRAD to use gradients.
84*b11c1e72Sjeremylt 
85*b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
86*b11c1e72Sjeremylt **/
87d7b241e6Sjeremylt static int CeedQFunctionFieldSet(struct CeedQFunctionField *f,
88d7b241e6Sjeremylt                                  const char *fieldname, CeedInt ncomp,
89d7b241e6Sjeremylt                                  CeedEvalMode emode) {
90d7b241e6Sjeremylt   size_t len = strlen(fieldname);
91d7b241e6Sjeremylt   char *tmp;
92d7b241e6Sjeremylt   int ierr =  CeedCalloc(len+1, &tmp); CeedChk(ierr);
93d7b241e6Sjeremylt   memcpy(tmp, fieldname, len+1);
94d7b241e6Sjeremylt   f->fieldname = tmp;
95d7b241e6Sjeremylt   f->ncomp = ncomp;
96d7b241e6Sjeremylt   f->emode = emode;
97d7b241e6Sjeremylt   return 0;
98d7b241e6Sjeremylt }
99d7b241e6Sjeremylt 
100*b11c1e72Sjeremylt /**
101*b11c1e72Sjeremylt   @brief Add a CEEDQFunction input
102*b11c1e72Sjeremylt 
103*b11c1e72Sjeremylt   @param qf         CeedQFunction
104*b11c1e72Sjeremylt   @param fieldname  Name of QFunction field
105*b11c1e72Sjeremylt   @param ncomp      Number of components per quadrature node
106*b11c1e72Sjeremylt   @param emode      \ref CEED_EVAL_NONE to use values directly,
107*b11c1e72Sjeremylt                       \ref CEED_EVAL_INTERP to use interpolated values,
108*b11c1e72Sjeremylt                       \ref CEED_EVAL_GRAD to use gradients.
109*b11c1e72Sjeremylt 
110*b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
111*b11c1e72Sjeremylt **/
112d7b241e6Sjeremylt int CeedQFunctionAddInput(CeedQFunction qf, const char *fieldname,
113d7b241e6Sjeremylt                           CeedInt ncomp, CeedEvalMode emode) {
114d7b241e6Sjeremylt   int ierr = CeedQFunctionFieldSet(&qf->inputfields[qf->numinputfields++],
115d7b241e6Sjeremylt                                    fieldname, ncomp, emode); CeedChk(ierr);
116d7b241e6Sjeremylt   return 0;
117d7b241e6Sjeremylt }
118d7b241e6Sjeremylt 
119*b11c1e72Sjeremylt /**
120*b11c1e72Sjeremylt   @brief Add a CEEDQFunction output
121*b11c1e72Sjeremylt 
122*b11c1e72Sjeremylt   @param qf         CeedQFunction
123*b11c1e72Sjeremylt   @param fieldname  Name of QFunction field
124*b11c1e72Sjeremylt   @param ncomp      Number of components per quadrature node
125*b11c1e72Sjeremylt   @param emode      \ref CEED_EVAL_NONE to use values directly,
126*b11c1e72Sjeremylt                       \ref CEED_EVAL_INTERP to use interpolated values,
127*b11c1e72Sjeremylt                       \ref CEED_EVAL_GRAD to use gradients.
128*b11c1e72Sjeremylt 
129*b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
130*b11c1e72Sjeremylt **/
131d7b241e6Sjeremylt int CeedQFunctionAddOutput(CeedQFunction qf, const char *fieldname,
132d7b241e6Sjeremylt                            CeedInt ncomp, CeedEvalMode emode) {
133d7b241e6Sjeremylt   if (emode == CEED_EVAL_WEIGHT)
134d7b241e6Sjeremylt     return CeedError(qf->ceed, 1,
135d7b241e6Sjeremylt                      "Cannot create qfunction output with CEED_EVAL_WEIGHT");
136d7b241e6Sjeremylt   int ierr = CeedQFunctionFieldSet(&qf->outputfields[qf->numoutputfields++],
137d7b241e6Sjeremylt                                    fieldname, ncomp, emode); CeedChk(ierr);
138d7b241e6Sjeremylt   return 0;
139d7b241e6Sjeremylt }
140d7b241e6Sjeremylt 
141d7b241e6Sjeremylt int CeedQFunctionGetNumArgs(CeedQFunction qf, CeedInt *numinput,
142d7b241e6Sjeremylt                             CeedInt *numoutput) {
143d7b241e6Sjeremylt   CeedInt nin = 0, nout = 0;
144d7b241e6Sjeremylt   for (CeedInt i=0; i<qf->numinputfields; i++) {
145d7b241e6Sjeremylt     CeedEvalMode emode = qf->inputfields[i].emode;
146d7b241e6Sjeremylt     if (emode == CEED_EVAL_NONE) nin++;  // Colocated field is input directly
147d7b241e6Sjeremylt     if (emode & CEED_EVAL_INTERP) nin++; // Interpolate to quadrature points
148d7b241e6Sjeremylt     if (emode & CEED_EVAL_GRAD) nin++;   // Gradients at quadrature points
149d7b241e6Sjeremylt   }
150d7b241e6Sjeremylt   for (CeedInt i=0; i<qf->numoutputfields; i++) {
151d7b241e6Sjeremylt     CeedEvalMode emode = qf->outputfields[i].emode;
152d7b241e6Sjeremylt     if (emode == CEED_EVAL_NONE) nout++;
153d7b241e6Sjeremylt     if (emode & CEED_EVAL_INTERP) nout++;
154d7b241e6Sjeremylt     if (emode & CEED_EVAL_GRAD) nout++;
155d7b241e6Sjeremylt   }
156d7b241e6Sjeremylt   if (numinput) *numinput = nin;
157d7b241e6Sjeremylt   if (numoutput) *numoutput = nout;
158d7b241e6Sjeremylt   return 0;
159d7b241e6Sjeremylt }
160d7b241e6Sjeremylt 
161d7b241e6Sjeremylt /**
162*b11c1e72Sjeremylt   @brief Set global context for a quadrature function
163*b11c1e72Sjeremylt 
164*b11c1e72Sjeremylt   @param qf       CeedQFunction
165*b11c1e72Sjeremylt   @param ctx      Context data to set
166*b11c1e72Sjeremylt   @param ctxsize  Size of context data values
167*b11c1e72Sjeremylt 
168*b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
169*b11c1e72Sjeremylt **/
170d7b241e6Sjeremylt int CeedQFunctionSetContext(CeedQFunction qf, void *ctx, size_t ctxsize) {
171d7b241e6Sjeremylt   qf->ctx = ctx;
172d7b241e6Sjeremylt   qf->ctxsize = ctxsize;
173d7b241e6Sjeremylt   return 0;
174d7b241e6Sjeremylt }
175d7b241e6Sjeremylt 
176*b11c1e72Sjeremylt /**
177*b11c1e72Sjeremylt   @brief Apply the action of a CeedQFunction
178*b11c1e72Sjeremylt 
179*b11c1e72Sjeremylt   @param qf      CeedQFunction
180*b11c1e72Sjeremylt   @param Q       Number of quadrature points
181*b11c1e72Sjeremylt   @param[in] u   Array of input data arrays
182*b11c1e72Sjeremylt   @param[out] v  Array of output data arrays
183*b11c1e72Sjeremylt 
184*b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
185*b11c1e72Sjeremylt **/
186d7b241e6Sjeremylt int CeedQFunctionApply(CeedQFunction qf, CeedInt Q,
187d7b241e6Sjeremylt                        const CeedScalar *const *u,
188d7b241e6Sjeremylt                        CeedScalar *const *v) {
189d7b241e6Sjeremylt   int ierr;
190d7b241e6Sjeremylt   if (!qf->Apply)
191d7b241e6Sjeremylt     return CeedError(qf->ceed, 1, "Backend does not support QFunctionApply");
192d7b241e6Sjeremylt   if (Q % qf->vlength)
193d7b241e6Sjeremylt     return CeedError(qf->ceed, 2,
194d7b241e6Sjeremylt                      "Number of quadrature points %d must be a multiple of %d",
195d7b241e6Sjeremylt                      Q, qf->vlength);
196d7b241e6Sjeremylt   ierr = qf->Apply(qf, Q, u, v); CeedChk(ierr);
197d7b241e6Sjeremylt   return 0;
198d7b241e6Sjeremylt }
199d7b241e6Sjeremylt 
200*b11c1e72Sjeremylt /**
201*b11c1e72Sjeremylt   @brief Destroy a CeedQFunction
202*b11c1e72Sjeremylt 
203*b11c1e72Sjeremylt   @param qf CeedQFunction to destroy
204*b11c1e72Sjeremylt 
205*b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
206*b11c1e72Sjeremylt **/
207d7b241e6Sjeremylt int CeedQFunctionDestroy(CeedQFunction *qf) {
208d7b241e6Sjeremylt   int ierr;
209d7b241e6Sjeremylt 
210d7b241e6Sjeremylt   if (!*qf || --(*qf)->refcount > 0) return 0;
211d7b241e6Sjeremylt   // Free field names
212d7b241e6Sjeremylt   for (int i=0; i<(*qf)->numinputfields; i++) {
213d7b241e6Sjeremylt     ierr = CeedFree(&(*qf)->inputfields[i].fieldname); CeedChk(ierr);
214d7b241e6Sjeremylt   }
215d7b241e6Sjeremylt   for (int i=0; i<(*qf)->numoutputfields; i++) {
216d7b241e6Sjeremylt     ierr = CeedFree(&(*qf)->outputfields[i].fieldname); CeedChk(ierr);
217d7b241e6Sjeremylt   }
218d7b241e6Sjeremylt   if ((*qf)->Destroy) {
219d7b241e6Sjeremylt     ierr = (*qf)->Destroy(*qf); CeedChk(ierr);
220d7b241e6Sjeremylt   }
221d7b241e6Sjeremylt   ierr = CeedFree(&(*qf)->focca); CeedChk(ierr);
222d7b241e6Sjeremylt   ierr = CeedDestroy(&(*qf)->ceed); CeedChk(ierr);
223d7b241e6Sjeremylt   ierr = CeedFree(qf); CeedChk(ierr);
224d7b241e6Sjeremylt   return 0;
225d7b241e6Sjeremylt }
226d7b241e6Sjeremylt 
227d7b241e6Sjeremylt /// @}
228