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