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