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