1*d7b241e6Sjeremylt // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at 2*d7b241e6Sjeremylt // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights 3*d7b241e6Sjeremylt // reserved. See files LICENSE and NOTICE for details. 4*d7b241e6Sjeremylt // 5*d7b241e6Sjeremylt // This file is part of CEED, a collection of benchmarks, miniapps, software 6*d7b241e6Sjeremylt // libraries and APIs for efficient high-order finite element and spectral 7*d7b241e6Sjeremylt // element discretizations for exascale applications. For more information and 8*d7b241e6Sjeremylt // source code availability see http://github.com/ceed. 9*d7b241e6Sjeremylt // 10*d7b241e6Sjeremylt // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC, 11*d7b241e6Sjeremylt // a collaborative effort of two U.S. Department of Energy organizations (Office 12*d7b241e6Sjeremylt // of Science and the National Nuclear Security Administration) responsible for 13*d7b241e6Sjeremylt // the planning and preparation of a capable exascale ecosystem, including 14*d7b241e6Sjeremylt // software, applications, hardware, advanced system engineering and early 15*d7b241e6Sjeremylt // testbed platforms, in support of the nation's exascale computing imperative. 16*d7b241e6Sjeremylt 17*d7b241e6Sjeremylt #include <ceed-impl.h> 18*d7b241e6Sjeremylt #include <string.h> 19*d7b241e6Sjeremylt 20*d7b241e6Sjeremylt /** 21*d7b241e6Sjeremylt @file 22*d7b241e6Sjeremylt Implementation of public CeedOperator interfaces 23*d7b241e6Sjeremylt 24*d7b241e6Sjeremylt @defgroup CeedOperator CeedOperator: composed FE-type operations on vectors 25*d7b241e6Sjeremylt @{ 26*d7b241e6Sjeremylt */ 27*d7b241e6Sjeremylt 28*d7b241e6Sjeremylt /** 29*d7b241e6Sjeremylt Create an operator from element restriction, basis, and QFunction 30*d7b241e6Sjeremylt 31*d7b241e6Sjeremylt @param ceed The Ceed library context on which to create the operator 32*d7b241e6Sjeremylt @param qf QFunction defining the action of the operator at quadrature points 33*d7b241e6Sjeremylt @param dqf QFunction defining the action of the Jacobian of @a qf (or NULL) 34*d7b241e6Sjeremylt @param dqfT QFunction defining the action of the transpose of the Jacobian 35*d7b241e6Sjeremylt of @a qf (or NULL) 36*d7b241e6Sjeremylt @param[out] op Newly created CeedOperator 37*d7b241e6Sjeremylt @return Error code, 0 on success 38*d7b241e6Sjeremylt */ 39*d7b241e6Sjeremylt int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, 40*d7b241e6Sjeremylt CeedQFunction dqfT, CeedOperator *op) { 41*d7b241e6Sjeremylt int ierr; 42*d7b241e6Sjeremylt 43*d7b241e6Sjeremylt if (!ceed->OperatorCreate) return CeedError(ceed, 1, 44*d7b241e6Sjeremylt "Backend does not support OperatorCreate"); 45*d7b241e6Sjeremylt ierr = CeedCalloc(1,op); CeedChk(ierr); 46*d7b241e6Sjeremylt (*op)->ceed = ceed; 47*d7b241e6Sjeremylt ceed->refcount++; 48*d7b241e6Sjeremylt (*op)->refcount = 1; 49*d7b241e6Sjeremylt (*op)->qf = qf; 50*d7b241e6Sjeremylt qf->refcount++; 51*d7b241e6Sjeremylt (*op)->dqf = dqf; 52*d7b241e6Sjeremylt if (dqf) dqf->refcount++; 53*d7b241e6Sjeremylt (*op)->dqfT = dqfT; 54*d7b241e6Sjeremylt if (dqfT) dqfT->refcount++; 55*d7b241e6Sjeremylt ierr = ceed->OperatorCreate(*op); CeedChk(ierr); 56*d7b241e6Sjeremylt return 0; 57*d7b241e6Sjeremylt } 58*d7b241e6Sjeremylt 59*d7b241e6Sjeremylt /** 60*d7b241e6Sjeremylt Provide a field to a CeedOperator for use by its CeedQFunction 61*d7b241e6Sjeremylt 62*d7b241e6Sjeremylt This function is used to specify both active and passive fields to a 63*d7b241e6Sjeremylt CeedOperator. For passive fields, a vector @arg v must be provided. Passive 64*d7b241e6Sjeremylt fields can inputs or outputs (updated in-place when operator is applied). 65*d7b241e6Sjeremylt 66*d7b241e6Sjeremylt Active fields must be specified using this function, but their data (in a 67*d7b241e6Sjeremylt CeedVector) is passed in CeedOperatorApply(). There can be at most one active 68*d7b241e6Sjeremylt input and at most one active output. 69*d7b241e6Sjeremylt 70*d7b241e6Sjeremylt @param op the operator on which to provide the field 71*d7b241e6Sjeremylt @param fieldname name of the field (to be matched with the name used by CeedQFunction) 72*d7b241e6Sjeremylt @param r element restriction 73*d7b241e6Sjeremylt @param b basis in which the field resides or CEED_BASIS_COLOCATED if collocated 74*d7b241e6Sjeremylt with quadrature points 75*d7b241e6Sjeremylt @param v vector to be used by CeedOperator, CEED_VECTOR_ACTIVE if field is 76*d7b241e6Sjeremylt active, or CEED_VECTOR_NONE if using CEED_EVAL_WEIGHT in the qfunction 77*d7b241e6Sjeremylt */ 78*d7b241e6Sjeremylt int CeedOperatorSetField(CeedOperator op, const char *fieldname, 79*d7b241e6Sjeremylt CeedElemRestriction r, CeedBasis b, 80*d7b241e6Sjeremylt CeedVector v) { 81*d7b241e6Sjeremylt int ierr; 82*d7b241e6Sjeremylt CeedInt numelements; 83*d7b241e6Sjeremylt ierr = CeedElemRestrictionGetNumElements(r, &numelements); CeedChk(ierr); 84*d7b241e6Sjeremylt if (op->numelements && op->numelements != numelements) 85*d7b241e6Sjeremylt return CeedError(op->ceed, 1, 86*d7b241e6Sjeremylt "ElemRestriction with %d elements incompatible with prior %d elements", 87*d7b241e6Sjeremylt numelements, op->numelements); 88*d7b241e6Sjeremylt op->numelements = numelements; 89*d7b241e6Sjeremylt 90*d7b241e6Sjeremylt if (b != CEED_BASIS_COLOCATED) { 91*d7b241e6Sjeremylt CeedInt numqpoints; 92*d7b241e6Sjeremylt ierr = CeedBasisGetNumQuadraturePoints(b, &numqpoints); CeedChk(ierr); 93*d7b241e6Sjeremylt if (op->numqpoints && op->numqpoints != numqpoints) 94*d7b241e6Sjeremylt return CeedError(op->ceed, 1, 95*d7b241e6Sjeremylt "Basis with %d quadrature points incompatible with prior %d points", 96*d7b241e6Sjeremylt numqpoints, op->numqpoints); 97*d7b241e6Sjeremylt op->numqpoints = numqpoints; 98*d7b241e6Sjeremylt } 99*d7b241e6Sjeremylt struct CeedOperatorField *ofield; 100*d7b241e6Sjeremylt for (CeedInt i=0; i<op->qf->numinputfields; i++) { 101*d7b241e6Sjeremylt if (!strcmp(fieldname, op->qf->inputfields[i].fieldname)) { 102*d7b241e6Sjeremylt ofield = &op->inputfields[i]; 103*d7b241e6Sjeremylt goto found; 104*d7b241e6Sjeremylt } 105*d7b241e6Sjeremylt } 106*d7b241e6Sjeremylt for (CeedInt i=0; i<op->qf->numoutputfields; i++) { 107*d7b241e6Sjeremylt if (!strcmp(fieldname, op->qf->outputfields[i].fieldname)) { 108*d7b241e6Sjeremylt ofield = &op->outputfields[i]; 109*d7b241e6Sjeremylt goto found; 110*d7b241e6Sjeremylt } 111*d7b241e6Sjeremylt } 112*d7b241e6Sjeremylt return CeedError(op->ceed, 1, "QFunction has no knowledge of field '%s'", 113*d7b241e6Sjeremylt fieldname); 114*d7b241e6Sjeremylt found: 115*d7b241e6Sjeremylt ofield->Erestrict = r; 116*d7b241e6Sjeremylt ofield->basis = b; 117*d7b241e6Sjeremylt ofield->vec = v; 118*d7b241e6Sjeremylt op->nfields += 1; 119*d7b241e6Sjeremylt return 0; 120*d7b241e6Sjeremylt } 121*d7b241e6Sjeremylt 122*d7b241e6Sjeremylt /** 123*d7b241e6Sjeremylt Apply CeedOperator to a vector 124*d7b241e6Sjeremylt 125*d7b241e6Sjeremylt This computes the action of the operator on the specified (active) input, 126*d7b241e6Sjeremylt yielding its (active) output. All inputs and outputs must be specified using 127*d7b241e6Sjeremylt CeedOperatorSetField(). 128*d7b241e6Sjeremylt 129*d7b241e6Sjeremylt @param op CeedOperator to apply 130*d7b241e6Sjeremylt @param in CeedVector containing input state or NULL if there are no active 131*d7b241e6Sjeremylt inputs 132*d7b241e6Sjeremylt @param out CeedVector to store result of applying operator (must be 133*d7b241e6Sjeremylt distinct from @a in) or NULL if there are no active outputs 134*d7b241e6Sjeremylt @param request Address of CeedRequest for non-blocking completion, else 135*d7b241e6Sjeremylt CEED_REQUEST_IMMEDIATE 136*d7b241e6Sjeremylt @return Error code, 0 on success 137*d7b241e6Sjeremylt */ 138*d7b241e6Sjeremylt int CeedOperatorApply(CeedOperator op, CeedVector in, 139*d7b241e6Sjeremylt CeedVector out, CeedRequest *request) { 140*d7b241e6Sjeremylt int ierr; 141*d7b241e6Sjeremylt Ceed ceed = op->ceed; 142*d7b241e6Sjeremylt CeedQFunction qf = op->qf; 143*d7b241e6Sjeremylt 144*d7b241e6Sjeremylt if (op->nfields == 0) return CeedError(ceed, 1, "No operator fields set"); 145*d7b241e6Sjeremylt if (op->nfields < qf->numinputfields + qf->numoutputfields) return CeedError( 146*d7b241e6Sjeremylt ceed, 1, "Not all operator fields set"); 147*d7b241e6Sjeremylt if (op->numelements == 0) return CeedError(ceed, 1, 148*d7b241e6Sjeremylt "At least one restriction required"); 149*d7b241e6Sjeremylt if (op->numqpoints == 0) return CeedError(ceed, 1, 150*d7b241e6Sjeremylt "At least one non-colocated basis required"); 151*d7b241e6Sjeremylt ierr = op->Apply(op, in, out, request); CeedChk(ierr); 152*d7b241e6Sjeremylt return 0; 153*d7b241e6Sjeremylt } 154*d7b241e6Sjeremylt 155*d7b241e6Sjeremylt /** 156*d7b241e6Sjeremylt Destroy a CeedOperator 157*d7b241e6Sjeremylt 158*d7b241e6Sjeremylt @param op CeedOperator to destroy 159*d7b241e6Sjeremylt @return Error code, 0 on success 160*d7b241e6Sjeremylt */ 161*d7b241e6Sjeremylt int CeedOperatorDestroy(CeedOperator *op) { 162*d7b241e6Sjeremylt int ierr; 163*d7b241e6Sjeremylt 164*d7b241e6Sjeremylt if (!*op || --(*op)->refcount > 0) return 0; 165*d7b241e6Sjeremylt if ((*op)->Destroy) { 166*d7b241e6Sjeremylt ierr = (*op)->Destroy(*op); CeedChk(ierr); 167*d7b241e6Sjeremylt } 168*d7b241e6Sjeremylt ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr); 169*d7b241e6Sjeremylt ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr); 170*d7b241e6Sjeremylt ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr); 171*d7b241e6Sjeremylt ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr); 172*d7b241e6Sjeremylt ierr = CeedFree(op); CeedChk(ierr); 173*d7b241e6Sjeremylt return 0; 174*d7b241e6Sjeremylt } 175*d7b241e6Sjeremylt 176*d7b241e6Sjeremylt /// @} 177