1 // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at 2 // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights 3 // 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-impl.h> 18 #include <ceed-backend.h> 19 #include <string.h> 20 21 /// @file 22 /// Implementation of public CeedOperator interfaces 23 /// 24 /// @addtogroup CeedOperator 25 /// @{ 26 27 /** 28 @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and 29 CeedElemRestriction can be associated with CeedQFunction fields with 30 \ref CeedOperatorSetField. 31 32 @param ceed A Ceed object where the CeedOperator will be created 33 @param qf QFunction defining the action of the operator at quadrature points 34 @param dqf QFunction defining the action of the Jacobian of @a qf (or NULL) 35 @param dqfT QFunction defining the action of the transpose of the Jacobian 36 of @a qf (or NULL) 37 @param[out] op Address of the variable where the newly created 38 CeedOperator will be stored 39 40 @return An error code: 0 - success, otherwise - failure 41 42 @ref Basic 43 */ 44 int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, 45 CeedQFunction dqfT, CeedOperator *op) { 46 int ierr; 47 48 if (!ceed->OperatorCreate) { 49 Ceed delegate; 50 ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr); 51 52 if (!delegate) 53 // LCOV_EXCL_START 54 return CeedError(ceed, 1, "Backend does not support OperatorCreate"); 55 // LCOV_EXCL_STOP 56 57 ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr); 58 return 0; 59 } 60 61 ierr = CeedCalloc(1, op); CeedChk(ierr); 62 (*op)->ceed = ceed; 63 ceed->refcount++; 64 (*op)->refcount = 1; 65 if (qf == CEED_QFUNCTION_NONE) 66 // LCOV_EXCL_START 67 return CeedError(ceed, 1, "Operator must have a valid QFunction."); 68 // LCOV_EXCL_STOP 69 (*op)->qf = qf; 70 qf->refcount++; 71 if (dqf && dqf != CEED_QFUNCTION_NONE) { 72 (*op)->dqf = dqf; 73 dqf->refcount++; 74 } 75 if (dqfT && dqfT != CEED_QFUNCTION_NONE) { 76 (*op)->dqfT = dqfT; 77 dqfT->refcount++; 78 } 79 ierr = CeedCalloc(16, &(*op)->inputfields); CeedChk(ierr); 80 ierr = CeedCalloc(16, &(*op)->outputfields); CeedChk(ierr); 81 ierr = ceed->OperatorCreate(*op); CeedChk(ierr); 82 return 0; 83 } 84 85 /** 86 @brief Create an operator that composes the action of several operators 87 88 @param ceed A Ceed object where the CeedOperator will be created 89 @param[out] op Address of the variable where the newly created 90 Composite CeedOperator will be stored 91 92 @return An error code: 0 - success, otherwise - failure 93 94 @ref Basic 95 */ 96 int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) { 97 int ierr; 98 99 if (!ceed->CompositeOperatorCreate) { 100 Ceed delegate; 101 ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr); 102 103 if (delegate) { 104 ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr); 105 return 0; 106 } 107 } 108 109 ierr = CeedCalloc(1, op); CeedChk(ierr); 110 (*op)->ceed = ceed; 111 ceed->refcount++; 112 (*op)->composite = true; 113 ierr = CeedCalloc(16, &(*op)->suboperators); CeedChk(ierr); 114 115 if (ceed->CompositeOperatorCreate) { 116 ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr); 117 } 118 return 0; 119 } 120 121 /** 122 @brief Provide a field to a CeedOperator for use by its CeedQFunction 123 124 This function is used to specify both active and passive fields to a 125 CeedOperator. For passive fields, a vector @arg v must be provided. Passive 126 fields can inputs or outputs (updated in-place when operator is applied). 127 128 Active fields must be specified using this function, but their data (in a 129 CeedVector) is passed in CeedOperatorApply(). There can be at most one active 130 input and at most one active output. 131 132 @param op CeedOperator on which to provide the field 133 @param fieldname Name of the field (to be matched with the name used by 134 CeedQFunction) 135 @param r CeedElemRestriction 136 @param lmode CeedTransposeMode which specifies the ordering of the 137 components of the l-vector used by this CeedOperatorField, 138 CEED_NOTRANSPOSE indicates the component is the 139 outermost index and CEED_TRANSPOSE indicates the component 140 is the innermost index in ordering of the l-vector 141 @param b CeedBasis in which the field resides or CEED_BASIS_COLLOCATED 142 if collocated with quadrature points 143 @param v CeedVector to be used by CeedOperator or CEED_VECTOR_ACTIVE 144 if field is active or CEED_VECTOR_NONE if using 145 CEED_EVAL_WEIGHT in the QFunction 146 147 @return An error code: 0 - success, otherwise - failure 148 149 @ref Basic 150 **/ 151 int CeedOperatorSetField(CeedOperator op, const char *fieldname, 152 CeedElemRestriction r, CeedTransposeMode lmode, 153 CeedBasis b, CeedVector v) { 154 int ierr; 155 if (op->composite) 156 // LCOV_EXCL_START 157 return CeedError(op->ceed, 1, "Cannot add field to composite operator."); 158 // LCOV_EXCL_STOP 159 if (!r) 160 // LCOV_EXCL_START 161 return CeedError(op->ceed, 1, 162 "ElemRestriction r for field \"%s\" must be non-NULL.", 163 fieldname); 164 // LCOV_EXCL_STOP 165 if (!b) 166 // LCOV_EXCL_START 167 return CeedError(op->ceed, 1, "Basis b for field \"%s\" must be non-NULL.", 168 fieldname); 169 // LCOV_EXCL_STOP 170 if (!v) 171 // LCOV_EXCL_START 172 return CeedError(op->ceed, 1, "Vector v for field \"%s\" must be non-NULL.", 173 fieldname); 174 // LCOV_EXCL_STOP 175 176 CeedInt numelements; 177 ierr = CeedElemRestrictionGetNumElements(r, &numelements); CeedChk(ierr); 178 if (op->hasrestriction && op->numelements != numelements) 179 // LCOV_EXCL_START 180 return CeedError(op->ceed, 1, 181 "ElemRestriction with %d elements incompatible with prior " 182 "%d elements", numelements, op->numelements); 183 // LCOV_EXCL_STOP 184 op->numelements = numelements; 185 op->hasrestriction = true; // Restriction set, but numelements may be 0 186 187 if (b != CEED_BASIS_COLLOCATED) { 188 CeedInt numqpoints; 189 ierr = CeedBasisGetNumQuadraturePoints(b, &numqpoints); CeedChk(ierr); 190 if (op->numqpoints && op->numqpoints != numqpoints) 191 // LCOV_EXCL_START 192 return CeedError(op->ceed, 1, "Basis with %d quadrature points " 193 "incompatible with prior %d points", numqpoints, 194 op->numqpoints); 195 // LCOV_EXCL_STOP 196 op->numqpoints = numqpoints; 197 } 198 CeedOperatorField *ofield; 199 for (CeedInt i=0; i<op->qf->numinputfields; i++) { 200 if (!strcmp(fieldname, (*op->qf->inputfields[i]).fieldname)) { 201 ofield = &op->inputfields[i]; 202 goto found; 203 } 204 } 205 for (CeedInt i=0; i<op->qf->numoutputfields; i++) { 206 if (!strcmp(fieldname, (*op->qf->outputfields[i]).fieldname)) { 207 ofield = &op->outputfields[i]; 208 goto found; 209 } 210 } 211 // LCOV_EXCL_START 212 return CeedError(op->ceed, 1, "QFunction has no knowledge of field '%s'", 213 fieldname); 214 // LCOV_EXCL_STOP 215 found: 216 ierr = CeedCalloc(1, ofield); CeedChk(ierr); 217 (*ofield)->Erestrict = r; 218 r->refcount += 1; 219 (*ofield)->lmode = lmode; 220 (*ofield)->basis = b; 221 if (b != CEED_BASIS_COLLOCATED) 222 b->refcount += 1; 223 (*ofield)->vec = v; 224 if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) 225 v->refcount += 1; 226 op->nfields += 1; 227 return 0; 228 } 229 230 /** 231 @brief Add a sub-operator to a composite CeedOperator 232 233 @param[out] compositeop Address of the composite CeedOperator 234 @param subop Address of the sub-operator CeedOperator 235 236 @return An error code: 0 - success, otherwise - failure 237 238 @ref Basic 239 */ 240 int CeedCompositeOperatorAddSub(CeedOperator compositeop, CeedOperator subop) { 241 if (!compositeop->composite) 242 // LCOV_EXCL_START 243 return CeedError(compositeop->ceed, 1, "CeedOperator is not a composite " 244 "operator"); 245 // LCOV_EXCL_STOP 246 247 if (compositeop->numsub == CEED_COMPOSITE_MAX) 248 // LCOV_EXCL_START 249 return CeedError(compositeop->ceed, 1, "Cannot add additional suboperators"); 250 // LCOV_EXCL_STOP 251 252 compositeop->suboperators[compositeop->numsub] = subop; 253 subop->refcount++; 254 compositeop->numsub++; 255 return 0; 256 } 257 258 /** 259 @brief Duplicate a CeedOperator with a reference Ceed to fallback for advanced 260 CeedOperator functionality 261 262 @param op CeedOperator to create fallback for 263 264 @return An error code: 0 - success, otherwise - failure 265 266 @ref Developer 267 **/ 268 int CeedOperatorCreateFallback(CeedOperator op) { 269 int ierr; 270 271 // Fallback Ceed 272 const char *resource, *fallbackresource; 273 ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr); 274 ierr = CeedGetOperatorFallbackResource(op->ceed, &fallbackresource); 275 CeedChk(ierr); 276 if (!strcmp(resource, fallbackresource)) 277 // LCOV_EXCL_START 278 return CeedError(op->ceed, 1, "Backend %s cannot create an operator" 279 "fallback to resource %s", resource, fallbackresource); 280 // LCOV_EXCL_STOP 281 282 Ceed ceedref; 283 ierr = CeedInit(fallbackresource, &ceedref); CeedChk(ierr); 284 ceedref->opfallbackparent = op->ceed; 285 op->ceed->opfallbackceed = ceedref; 286 287 // Clone Op 288 CeedOperator opref; 289 ierr = CeedCalloc(1, &opref); CeedChk(ierr); 290 memcpy(opref, op, sizeof(*opref)); CeedChk(ierr); 291 opref->data = NULL; 292 opref->setupdone = 0; 293 opref->ceed = ceedref; 294 ierr = ceedref->OperatorCreate(opref); CeedChk(ierr); 295 op->opfallback = opref; 296 297 // Clone QF 298 CeedQFunction qfref; 299 ierr = CeedCalloc(1, &qfref); CeedChk(ierr); 300 memcpy(qfref, (op->qf), sizeof(*qfref)); CeedChk(ierr); 301 qfref->data = NULL; 302 qfref->ceed = ceedref; 303 ierr = ceedref->QFunctionCreate(qfref); CeedChk(ierr); 304 opref->qf = qfref; 305 op->qffallback = qfref; 306 307 return 0; 308 } 309 310 /** 311 @brief Check if a CeedOperator is ready to be used. 312 313 @param[in] ceed Ceed object for error handling 314 @param[in] op CeedOperator to check 315 316 @return An error code: 0 - success, otherwise - failure 317 318 @ref Basic 319 **/ 320 static int CeedOperatorCheckReady(Ceed ceed, CeedOperator op) { 321 CeedQFunction qf = op->qf; 322 323 if (op->composite) { 324 if (!op->numsub) 325 // LCOV_EXCL_START 326 return CeedError(ceed, 1, "No suboperators set"); 327 // LCOV_EXCL_STOP 328 } else { 329 if (op->nfields == 0) 330 // LCOV_EXCL_START 331 return CeedError(ceed, 1, "No operator fields set"); 332 // LCOV_EXCL_STOP 333 if (op->nfields < qf->numinputfields + qf->numoutputfields) 334 // LCOV_EXCL_START 335 return CeedError(ceed, 1, "Not all operator fields set"); 336 // LCOV_EXCL_STOP 337 if (!op->hasrestriction) 338 // LCOV_EXCL_START 339 return CeedError(ceed, 1,"At least one restriction required"); 340 // LCOV_EXCL_STOP 341 if (op->numqpoints == 0) 342 // LCOV_EXCL_START 343 return CeedError(ceed, 1,"At least one non-collocated basis required"); 344 // LCOV_EXCL_STOP 345 } 346 347 return 0; 348 } 349 350 /** 351 @brief Assemble a linear CeedQFunction associated with a CeedOperator 352 353 This returns a CeedVector containing a matrix at each quadrature point 354 providing the action of the CeedQFunction associated with the CeedOperator. 355 The vector 'assembled' is of shape 356 [num_elements, num_input_fields, num_output_fields, num_quad_points] 357 and contains column-major matrices representing the action of the 358 CeedQFunction for a corresponding quadrature point on an element. Inputs and 359 outputs are in the order provided by the user when adding CeedOperator fields. 360 For example, a QFunction with inputs 'u' and 'gradu' and outputs 'gradv' and 361 'v', provided in that order, would result in an assembled QFunction that 362 consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting 363 on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v]. 364 365 @param op CeedOperator to assemble CeedQFunction 366 @param[out] assembled CeedVector to store assembled CeedQFunction at 367 quadrature points 368 @param[out] rstr CeedElemRestriction for CeedVector containing assembled 369 CeedQFunction 370 @param request Address of CeedRequest for non-blocking completion, else 371 CEED_REQUEST_IMMEDIATE 372 373 @return An error code: 0 - success, otherwise - failure 374 375 @ref Basic 376 **/ 377 int CeedOperatorAssembleLinearQFunction(CeedOperator op, CeedVector *assembled, 378 CeedElemRestriction *rstr, 379 CeedRequest *request) { 380 int ierr; 381 Ceed ceed = op->ceed; 382 ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr); 383 384 if (op->AssembleLinearQFunction) { 385 ierr = op->AssembleLinearQFunction(op, assembled, rstr, request); 386 CeedChk(ierr); 387 } else { 388 // Fallback to reference Ceed 389 if (!op->opfallback) { 390 ierr = CeedOperatorCreateFallback(op); CeedChk(ierr); 391 } 392 // Assemble 393 ierr = op->opfallback->AssembleLinearQFunction(op->opfallback, assembled, 394 rstr, request); CeedChk(ierr); 395 } 396 397 return 0; 398 } 399 400 /** 401 @brief Assemble the diagonal of a square linear Operator 402 403 This returns a CeedVector containing the diagonal of a linear CeedOperator. 404 405 @param op CeedOperator to assemble CeedQFunction 406 @param[out] assembled CeedVector to store assembled CeedOperator diagonal 407 @param request Address of CeedRequest for non-blocking completion, else 408 CEED_REQUEST_IMMEDIATE 409 410 @return An error code: 0 - success, otherwise - failure 411 412 @ref Basic 413 **/ 414 int CeedOperatorAssembleLinearDiagonal(CeedOperator op, CeedVector *assembled, 415 CeedRequest *request) { 416 int ierr; 417 Ceed ceed = op->ceed; 418 ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr); 419 420 // Use backend version, if available 421 if (op->AssembleLinearDiagonal) { 422 ierr = op->AssembleLinearDiagonal(op, assembled, request); CeedChk(ierr); 423 return 0; 424 } 425 426 // Assemble QFunction 427 CeedQFunction qf = op->qf; 428 CeedVector assembledqf; 429 CeedElemRestriction rstr; 430 ierr = CeedOperatorAssembleLinearQFunction(op, &assembledqf, &rstr, request); 431 CeedChk(ierr); 432 ierr = CeedElemRestrictionDestroy(&rstr); CeedChk(ierr); 433 434 // Determine active input basis 435 CeedInt numemodein = 0, ncomp, dim = 1; 436 CeedEvalMode *emodein = NULL; 437 CeedBasis basisin = NULL; 438 CeedElemRestriction rstrin = NULL; 439 for (CeedInt i=0; i<qf->numinputfields; i++) 440 if (op->inputfields[i]->vec == CEED_VECTOR_ACTIVE) { 441 ierr = CeedOperatorFieldGetBasis(op->inputfields[i], &basisin); 442 CeedChk(ierr); 443 ierr = CeedBasisGetNumComponents(basisin, &ncomp); CeedChk(ierr); 444 ierr = CeedBasisGetDimension(basisin, &dim); CeedChk(ierr); 445 ierr = CeedOperatorFieldGetElemRestriction(op->inputfields[i], &rstrin); 446 CeedChk(ierr); 447 CeedEvalMode emode; 448 ierr = CeedQFunctionFieldGetEvalMode(qf->inputfields[i], &emode); 449 CeedChk(ierr); 450 switch (emode) { 451 case CEED_EVAL_NONE: 452 case CEED_EVAL_INTERP: 453 ierr = CeedRealloc(numemodein + 1, &emodein); CeedChk(ierr); 454 emodein[numemodein] = emode; 455 numemodein += 1; 456 break; 457 case CEED_EVAL_GRAD: 458 ierr = CeedRealloc(numemodein + dim, &emodein); CeedChk(ierr); 459 for (CeedInt d=0; d<dim; d++) 460 emodein[numemodein+d] = emode; 461 numemodein += dim; 462 break; 463 case CEED_EVAL_WEIGHT: 464 case CEED_EVAL_DIV: 465 case CEED_EVAL_CURL: 466 break; // Caught by QF Assembly 467 } 468 } 469 470 // Determine active output basis 471 CeedInt numemodeout = 0; 472 CeedEvalMode *emodeout = NULL; 473 CeedBasis basisout = NULL; 474 CeedElemRestriction rstrout = NULL; 475 CeedTransposeMode lmodeout = CEED_NOTRANSPOSE; 476 for (CeedInt i=0; i<qf->numoutputfields; i++) 477 if (op->outputfields[i]->vec == CEED_VECTOR_ACTIVE) { 478 ierr = CeedOperatorFieldGetBasis(op->outputfields[i], &basisout); 479 CeedChk(ierr); 480 ierr = CeedOperatorFieldGetElemRestriction(op->outputfields[i], &rstrout); 481 CeedChk(ierr); 482 ierr = CeedOperatorFieldGetLMode(op->outputfields[i], &lmodeout); 483 CeedChk(ierr); 484 CeedEvalMode emode; 485 ierr = CeedQFunctionFieldGetEvalMode(qf->outputfields[i], &emode); 486 CeedChk(ierr); 487 switch (emode) { 488 case CEED_EVAL_NONE: 489 case CEED_EVAL_INTERP: 490 ierr = CeedRealloc(numemodeout + 1, &emodeout); CeedChk(ierr); 491 emodeout[numemodeout] = emode; 492 numemodeout += 1; 493 break; 494 case CEED_EVAL_GRAD: 495 ierr = CeedRealloc(numemodeout + dim, &emodeout); CeedChk(ierr); 496 for (CeedInt d=0; d<dim; d++) 497 emodeout[numemodeout+d] = emode; 498 numemodeout += dim; 499 break; 500 case CEED_EVAL_WEIGHT: 501 case CEED_EVAL_DIV: 502 case CEED_EVAL_CURL: 503 break; // Caught by QF Assembly 504 } 505 } 506 507 // Create diagonal vector 508 CeedVector elemdiag; 509 ierr = CeedElemRestrictionCreateVector(rstrin, assembled, &elemdiag); 510 CeedChk(ierr); 511 512 // Assemble element operator diagonals 513 CeedScalar *elemdiagarray, *assembledqfarray; 514 ierr = CeedVectorSetValue(elemdiag, 0.0); CeedChk(ierr); 515 ierr = CeedVectorGetArray(elemdiag, CEED_MEM_HOST, &elemdiagarray); 516 CeedChk(ierr); 517 ierr = CeedVectorGetArray(assembledqf, CEED_MEM_HOST, &assembledqfarray); 518 CeedChk(ierr); 519 CeedInt nelem, nnodes, nqpts; 520 ierr = CeedElemRestrictionGetNumElements(rstrin, &nelem); CeedChk(ierr); 521 ierr = CeedBasisGetNumNodes(basisin, &nnodes); CeedChk(ierr); 522 ierr = CeedBasisGetNumQuadraturePoints(basisin, &nqpts); CeedChk(ierr); 523 // Compute the diagonal of B^T D B 524 // Each node, qpt pair 525 for (CeedInt n=0; n<nnodes; n++) 526 for (CeedInt q=0; q<nqpts; q++) { 527 CeedInt dout = -1; 528 // Each basis eval mode pair 529 for (CeedInt eout=0; eout<numemodeout; eout++) { 530 CeedScalar bt = 1.0; 531 if (emodeout[eout] == CEED_EVAL_GRAD) 532 dout += 1; 533 ierr = CeedBasisGetValue(basisout, emodeout[eout], q, n, dout, &bt); 534 CeedChk(ierr); 535 CeedInt din = -1; 536 for (CeedInt ein=0; ein<numemodein; ein++) { 537 CeedScalar b = 0.0; 538 if (emodein[ein] == CEED_EVAL_GRAD) 539 din += 1; 540 ierr = CeedBasisGetValue(basisin, emodein[ein], q, n, din, &b); 541 CeedChk(ierr); 542 // Each element and component 543 for (CeedInt e=0; e<nelem; e++) 544 for (CeedInt cout=0; cout<ncomp; cout++) { 545 CeedScalar db = 0.0; 546 for (CeedInt cin=0; cin<ncomp; cin++) 547 db += assembledqfarray[((((e*numemodein+ein)*ncomp+cin)* 548 numemodeout+eout)*ncomp+cout)*nqpts+q]*b; 549 elemdiagarray[(e*ncomp+cout)*nnodes+n] += bt * db; 550 } 551 } 552 } 553 } 554 555 ierr = CeedVectorRestoreArray(elemdiag, &elemdiagarray); CeedChk(ierr); 556 ierr = CeedVectorRestoreArray(assembledqf, &assembledqfarray); CeedChk(ierr); 557 558 // Assemble local operator diagonal 559 ierr = CeedVectorSetValue(*assembled, 0.0); CeedChk(ierr); 560 ierr = CeedElemRestrictionApply(rstrout, CEED_TRANSPOSE, lmodeout, elemdiag, 561 *assembled, request); CeedChk(ierr); 562 563 // Cleanup 564 ierr = CeedVectorDestroy(&assembledqf); CeedChk(ierr); 565 ierr = CeedVectorDestroy(&elemdiag); CeedChk(ierr); 566 ierr = CeedFree(&emodein); CeedChk(ierr); 567 ierr = CeedFree(&emodeout); CeedChk(ierr); 568 569 return 0; 570 } 571 572 /** 573 @brief Apply CeedOperator to a vector and overwrite output vector 574 575 This computes the action of the operator on the specified (active) input, 576 yielding its (active) output. All inputs and outputs must be specified using 577 CeedOperatorSetField(). 578 579 @param op CeedOperator to apply 580 @param[in] in CeedVector containing input state or NULL if there are no 581 active inputs 582 @param[out] out CeedVector to store result of applying operator (must be 583 distinct from @a in) or NULL if there are no active outputs 584 @param request Address of CeedRequest for non-blocking completion, else 585 CEED_REQUEST_IMMEDIATE 586 587 @return An error code: 0 - success, otherwise - failure 588 589 @ref Basic 590 **/ 591 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, 592 CeedRequest *request) { 593 int ierr; 594 Ceed ceed = op->ceed; 595 ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr); 596 597 if (op->numelements) { 598 // Standard Operator 599 if (op->Apply) { 600 ierr = op->Apply(op, in, out, request); CeedChk(ierr); 601 } else { 602 // Zero all output vectors 603 CeedQFunction qf = op->qf; 604 for (CeedInt i=0; i<qf->numoutputfields; i++) { 605 CeedVector vec = op->outputfields[i]->vec; 606 if (vec == CEED_VECTOR_ACTIVE) 607 vec = out; 608 if (vec != CEED_VECTOR_NONE) { 609 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 610 } 611 } 612 // Apply 613 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 614 } 615 } else if (op->composite) { 616 // Composite Operator 617 if (op->ApplyComposite) { 618 ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr); 619 } else { 620 CeedInt numsub; 621 ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr); 622 CeedOperator *suboperators; 623 ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr); 624 625 // Zero all output vectors 626 if (out != CEED_VECTOR_NONE) { 627 ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr); 628 } 629 for (CeedInt i=0; i<numsub; i++) { 630 for (CeedInt j=0; j<suboperators[i]->qf->numoutputfields; j++) { 631 CeedVector vec = suboperators[i]->outputfields[j]->vec; 632 if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) { 633 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 634 } 635 } 636 } 637 // Apply 638 for (CeedInt i=0; i<op->numsub; i++) { 639 ierr = CeedOperatorApplyAdd(op->suboperators[i], in, out, request); 640 CeedChk(ierr); 641 } 642 } 643 } 644 645 return 0; 646 } 647 648 /** 649 @brief Apply CeedOperator to a vector and add result to output vector 650 651 This computes the action of the operator on the specified (active) input, 652 yielding its (active) output. All inputs and outputs must be specified using 653 CeedOperatorSetField(). 654 655 @param op CeedOperator to apply 656 @param[in] in CeedVector containing input state or NULL if there are no 657 active inputs 658 @param[out] out CeedVector to sum in result of applying operator (must be 659 distinct from @a in) or NULL if there are no active outputs 660 @param request Address of CeedRequest for non-blocking completion, else 661 CEED_REQUEST_IMMEDIATE 662 663 @return An error code: 0 - success, otherwise - failure 664 665 @ref Basic 666 **/ 667 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, 668 CeedRequest *request) { 669 int ierr; 670 Ceed ceed = op->ceed; 671 ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr); 672 673 if (op->numelements) { 674 // Standard Operator 675 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 676 } else if (op->composite) { 677 // Composite Operator 678 if (op->ApplyAddComposite) { 679 ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr); 680 } else { 681 CeedInt numsub; 682 ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr); 683 CeedOperator *suboperators; 684 ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr); 685 686 for (CeedInt i=0; i<numsub; i++) { 687 ierr = CeedOperatorApplyAdd(suboperators[i], in, out, request); 688 CeedChk(ierr); 689 } 690 } 691 } 692 693 return 0; 694 } 695 696 /** 697 @brief Get the Ceed associated with a CeedOperator 698 699 @param op CeedOperator 700 @param[out] ceed Variable to store Ceed 701 702 @return An error code: 0 - success, otherwise - failure 703 704 @ref Advanced 705 **/ 706 707 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) { 708 *ceed = op->ceed; 709 return 0; 710 } 711 712 /** 713 @brief Get the number of elements associated with a CeedOperator 714 715 @param op CeedOperator 716 @param[out] numelem Variable to store number of elements 717 718 @return An error code: 0 - success, otherwise - failure 719 720 @ref Advanced 721 **/ 722 723 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) { 724 if (op->composite) 725 // LCOV_EXCL_START 726 return CeedError(op->ceed, 1, "Not defined for composite operator"); 727 // LCOV_EXCL_STOP 728 729 *numelem = op->numelements; 730 return 0; 731 } 732 733 /** 734 @brief Get the number of quadrature points associated with a CeedOperator 735 736 @param op CeedOperator 737 @param[out] numqpts Variable to store vector number of quadrature points 738 739 @return An error code: 0 - success, otherwise - failure 740 741 @ref Advanced 742 **/ 743 744 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) { 745 if (op->composite) 746 // LCOV_EXCL_START 747 return CeedError(op->ceed, 1, "Not defined for composite operator"); 748 // LCOV_EXCL_STOP 749 750 *numqpts = op->numqpoints; 751 return 0; 752 } 753 754 /** 755 @brief Get the number of arguments associated with a CeedOperator 756 757 @param op CeedOperator 758 @param[out] numargs Variable to store vector number of arguments 759 760 @return An error code: 0 - success, otherwise - failure 761 762 @ref Advanced 763 **/ 764 765 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) { 766 if (op->composite) 767 // LCOV_EXCL_START 768 return CeedError(op->ceed, 1, "Not defined for composite operators"); 769 // LCOV_EXCL_STOP 770 771 *numargs = op->nfields; 772 return 0; 773 } 774 775 /** 776 @brief Get the setup status of a CeedOperator 777 778 @param op CeedOperator 779 @param[out] setupdone Variable to store setup status 780 781 @return An error code: 0 - success, otherwise - failure 782 783 @ref Advanced 784 **/ 785 786 int CeedOperatorGetSetupStatus(CeedOperator op, bool *setupdone) { 787 *setupdone = op->setupdone; 788 return 0; 789 } 790 791 /** 792 @brief Get the QFunction associated with a CeedOperator 793 794 @param op CeedOperator 795 @param[out] qf Variable to store QFunction 796 797 @return An error code: 0 - success, otherwise - failure 798 799 @ref Advanced 800 **/ 801 802 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) { 803 if (op->composite) 804 // LCOV_EXCL_START 805 return CeedError(op->ceed, 1, "Not defined for composite operator"); 806 // LCOV_EXCL_STOP 807 808 *qf = op->qf; 809 return 0; 810 } 811 812 /** 813 @brief Get the number of suboperators associated with a CeedOperator 814 815 @param op CeedOperator 816 @param[out] numsub Variable to store number of suboperators 817 818 @return An error code: 0 - success, otherwise - failure 819 820 @ref Advanced 821 **/ 822 823 int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) { 824 if (!op->composite) 825 // LCOV_EXCL_START 826 return CeedError(op->ceed, 1, "Not a composite operator"); 827 // LCOV_EXCL_STOP 828 829 *numsub = op->numsub; 830 return 0; 831 } 832 833 /** 834 @brief Get the list of suboperators associated with a CeedOperator 835 836 @param op CeedOperator 837 @param[out] suboperators Variable to store list of suboperators 838 839 @return An error code: 0 - success, otherwise - failure 840 841 @ref Advanced 842 **/ 843 844 int CeedOperatorGetSubList(CeedOperator op, CeedOperator **suboperators) { 845 if (!op->composite) 846 // LCOV_EXCL_START 847 return CeedError(op->ceed, 1, "Not a composite operator"); 848 // LCOV_EXCL_STOP 849 850 *suboperators = op->suboperators; 851 return 0; 852 } 853 854 /** 855 @brief Set the backend data of a CeedOperator 856 857 @param[out] op CeedOperator 858 @param data Data to set 859 860 @return An error code: 0 - success, otherwise - failure 861 862 @ref Advanced 863 **/ 864 865 int CeedOperatorSetData(CeedOperator op, void **data) { 866 op->data = *data; 867 return 0; 868 } 869 870 /** 871 @brief Get the backend data of a CeedOperator 872 873 @param op CeedOperator 874 @param[out] data Variable to store data 875 876 @return An error code: 0 - success, otherwise - failure 877 878 @ref Advanced 879 **/ 880 881 int CeedOperatorGetData(CeedOperator op, void **data) { 882 *data = op->data; 883 return 0; 884 } 885 886 /** 887 @brief Set the setup flag of a CeedOperator to True 888 889 @param op CeedOperator 890 891 @return An error code: 0 - success, otherwise - failure 892 893 @ref Advanced 894 **/ 895 896 int CeedOperatorSetSetupDone(CeedOperator op) { 897 op->setupdone = 1; 898 return 0; 899 } 900 901 /** 902 @brief View a field of a CeedOperator 903 904 @param[in] field Operator field to view 905 @param[in] fieldnumber Number of field being viewed 906 @param[in] stream Stream to view to, e.g., stdout 907 908 @return An error code: 0 - success, otherwise - failure 909 910 @ref Utility 911 **/ 912 static int CeedOperatorFieldView(CeedOperatorField field, 913 CeedQFunctionField qffield, 914 CeedInt fieldnumber, bool sub, bool in, 915 FILE *stream) { 916 const char *pre = sub ? " " : ""; 917 const char *inout = in ? "Input" : "Output"; 918 919 fprintf(stream, "%s %s Field [%d]:\n" 920 "%s Name: \"%s\"\n" 921 "%s Lmode: \"%s\"\n", 922 pre, inout, fieldnumber, pre, qffield->fieldname, 923 pre, CeedTransposeModes[field->lmode]); 924 925 if (field->basis == CEED_BASIS_COLLOCATED) 926 fprintf(stream, "%s Collocated basis\n", pre); 927 928 if (field->vec == CEED_VECTOR_ACTIVE) 929 fprintf(stream, "%s Active vector\n", pre); 930 else if (field->vec == CEED_VECTOR_NONE) 931 fprintf(stream, "%s No vector\n", pre); 932 933 return 0; 934 } 935 936 /** 937 @brief View a single CeedOperator 938 939 @param[in] op CeedOperator to view 940 @param[in] stream Stream to write; typically stdout/stderr or a file 941 942 @return Error code: 0 - success, otherwise - failure 943 944 @ref Utility 945 **/ 946 int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) { 947 int ierr; 948 const char *pre = sub ? " " : ""; 949 950 CeedInt totalfields; 951 ierr = CeedOperatorGetNumArgs(op, &totalfields); CeedChk(ierr); 952 953 fprintf(stream, "%s %d Field%s\n", pre, totalfields, totalfields>1 ? "s" : ""); 954 955 fprintf(stream, "%s %d Input Field%s:\n", pre, op->qf->numinputfields, 956 op->qf->numinputfields>1 ? "s" : ""); 957 for (CeedInt i=0; i<op->qf->numinputfields; i++) { 958 ierr = CeedOperatorFieldView(op->inputfields[i], op->qf->inputfields[i], 959 i, sub, 1, stream); CeedChk(ierr); 960 } 961 962 fprintf(stream, "%s %d Output Field%s:\n", pre, op->qf->numoutputfields, 963 op->qf->numoutputfields>1 ? "s" : ""); 964 for (CeedInt i=0; i<op->qf->numoutputfields; i++) { 965 ierr = CeedOperatorFieldView(op->outputfields[i], op->qf->inputfields[i], 966 i, sub, 0, stream); CeedChk(ierr); 967 } 968 969 return 0; 970 } 971 972 /** 973 @brief View a CeedOperator 974 975 @param[in] op CeedOperator to view 976 @param[in] stream Stream to write; typically stdout/stderr or a file 977 978 @return Error code: 0 - success, otherwise - failure 979 980 @ref Utility 981 **/ 982 int CeedOperatorView(CeedOperator op, FILE *stream) { 983 int ierr; 984 985 if (op->composite) { 986 fprintf(stream, "Composite CeedOperator\n"); 987 988 for (CeedInt i=0; i<op->numsub; i++) { 989 fprintf(stream, " SubOperator [%d]:\n", i); 990 ierr = CeedOperatorSingleView(op->suboperators[i], 1, stream); 991 CeedChk(ierr); 992 } 993 } else { 994 fprintf(stream, "CeedOperator\n"); 995 ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr); 996 } 997 998 return 0; 999 } 1000 1001 /** 1002 @brief Get the CeedOperatorFields of a CeedOperator 1003 1004 @param op CeedOperator 1005 @param[out] inputfields Variable to store inputfields 1006 @param[out] outputfields Variable to store outputfields 1007 1008 @return An error code: 0 - success, otherwise - failure 1009 1010 @ref Advanced 1011 **/ 1012 1013 int CeedOperatorGetFields(CeedOperator op, CeedOperatorField **inputfields, 1014 CeedOperatorField **outputfields) { 1015 if (op->composite) 1016 // LCOV_EXCL_START 1017 return CeedError(op->ceed, 1, "Not defined for composite operator"); 1018 // LCOV_EXCL_STOP 1019 1020 if (inputfields) *inputfields = op->inputfields; 1021 if (outputfields) *outputfields = op->outputfields; 1022 return 0; 1023 } 1024 1025 /** 1026 @brief Get the L vector CeedTransposeMode of a CeedOperatorField 1027 1028 @param opfield CeedOperatorField 1029 @param[out] lmode Variable to store CeedTransposeMode 1030 1031 @return An error code: 0 - success, otherwise - failure 1032 1033 @ref Advanced 1034 **/ 1035 1036 int CeedOperatorFieldGetLMode(CeedOperatorField opfield, 1037 CeedTransposeMode *lmode) { 1038 *lmode = opfield->lmode; 1039 return 0; 1040 } 1041 1042 /** 1043 @brief Get the CeedElemRestriction of a CeedOperatorField 1044 1045 @param opfield CeedOperatorField 1046 @param[out] rstr Variable to store CeedElemRestriction 1047 1048 @return An error code: 0 - success, otherwise - failure 1049 1050 @ref Advanced 1051 **/ 1052 1053 int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield, 1054 CeedElemRestriction *rstr) { 1055 *rstr = opfield->Erestrict; 1056 return 0; 1057 } 1058 1059 /** 1060 @brief Get the CeedBasis of a CeedOperatorField 1061 1062 @param opfield CeedOperatorField 1063 @param[out] basis Variable to store CeedBasis 1064 1065 @return An error code: 0 - success, otherwise - failure 1066 1067 @ref Advanced 1068 **/ 1069 1070 int CeedOperatorFieldGetBasis(CeedOperatorField opfield, CeedBasis *basis) { 1071 *basis = opfield->basis; 1072 return 0; 1073 } 1074 1075 /** 1076 @brief Get the CeedVector of a CeedOperatorField 1077 1078 @param opfield CeedOperatorField 1079 @param[out] vec Variable to store CeedVector 1080 1081 @return An error code: 0 - success, otherwise - failure 1082 1083 @ref Advanced 1084 **/ 1085 1086 int CeedOperatorFieldGetVector(CeedOperatorField opfield, CeedVector *vec) { 1087 *vec = opfield->vec; 1088 return 0; 1089 } 1090 1091 /** 1092 @brief Destroy a CeedOperator 1093 1094 @param op CeedOperator to destroy 1095 1096 @return An error code: 0 - success, otherwise - failure 1097 1098 @ref Basic 1099 **/ 1100 int CeedOperatorDestroy(CeedOperator *op) { 1101 int ierr; 1102 1103 if (!*op || --(*op)->refcount > 0) return 0; 1104 if ((*op)->Destroy) { 1105 ierr = (*op)->Destroy(*op); CeedChk(ierr); 1106 } 1107 ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr); 1108 // Free fields 1109 for (int i=0; i<(*op)->nfields; i++) 1110 if ((*op)->inputfields[i]) { 1111 ierr = CeedElemRestrictionDestroy(&(*op)->inputfields[i]->Erestrict); 1112 CeedChk(ierr); 1113 if ((*op)->inputfields[i]->basis != CEED_BASIS_COLLOCATED) { 1114 ierr = CeedBasisDestroy(&(*op)->inputfields[i]->basis); CeedChk(ierr); 1115 } 1116 if ((*op)->inputfields[i]->vec != CEED_VECTOR_ACTIVE && 1117 (*op)->inputfields[i]->vec != CEED_VECTOR_NONE ) { 1118 ierr = CeedVectorDestroy(&(*op)->inputfields[i]->vec); CeedChk(ierr); 1119 } 1120 ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr); 1121 } 1122 for (int i=0; i<(*op)->nfields; i++) 1123 if ((*op)->outputfields[i]) { 1124 ierr = CeedElemRestrictionDestroy(&(*op)->outputfields[i]->Erestrict); 1125 CeedChk(ierr); 1126 if ((*op)->outputfields[i]->basis != CEED_BASIS_COLLOCATED) { 1127 ierr = CeedBasisDestroy(&(*op)->outputfields[i]->basis); CeedChk(ierr); 1128 } 1129 if ((*op)->outputfields[i]->vec != CEED_VECTOR_ACTIVE && 1130 (*op)->outputfields[i]->vec != CEED_VECTOR_NONE ) { 1131 ierr = CeedVectorDestroy(&(*op)->outputfields[i]->vec); CeedChk(ierr); 1132 } 1133 ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr); 1134 } 1135 // Destroy suboperators 1136 for (int i=0; i<(*op)->numsub; i++) 1137 if ((*op)->suboperators[i]) { 1138 ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr); 1139 } 1140 ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr); 1141 ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr); 1142 ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr); 1143 1144 // Destroy fallback 1145 if ((*op)->opfallback) { 1146 ierr = (*op)->qffallback->Destroy((*op)->qffallback); CeedChk(ierr); 1147 ierr = CeedFree(&(*op)->qffallback); CeedChk(ierr); 1148 ierr = (*op)->opfallback->Destroy((*op)->opfallback); CeedChk(ierr); 1149 ierr = CeedFree(&(*op)->opfallback); CeedChk(ierr); 1150 } 1151 1152 ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr); 1153 ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr); 1154 ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr); 1155 ierr = CeedFree(op); CeedChk(ierr); 1156 return 0; 1157 } 1158 1159 /// @} 1160