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 // LCOV_EXCL_START 105 return CeedError(ceed, 1, "Backend does not support " 106 "CompositeOperatorCreate"); 107 // LCOV_EXCL_STOP 108 109 ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr); 110 return 0; 111 } 112 113 ierr = CeedCalloc(1,op); CeedChk(ierr); 114 (*op)->ceed = ceed; 115 ceed->refcount++; 116 (*op)->composite = true; 117 ierr = CeedCalloc(16, &(*op)->suboperators); CeedChk(ierr); 118 ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr); 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 Address of the composite CeedOperator 235 @param subop Address of the 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 Assemble a linear CeedQFunction associated with a CeedOperator 313 314 This returns a CeedVector containing a matrix at each quadrature point 315 providing the action of the CeedQFunction associated with the CeedOperator. 316 The vector 'assembled' is of shape 317 [num_elements, num_input_fields, num_output_fields, num_quad_points] 318 and contains column-major matrices representing the action of the 319 CeedQFunction for a corresponding quadrature point on an element. Inputs and 320 outputs are in the order provided by the user when adding CeedOperator fields. 321 For example, a QFunction with inputs 'u' and 'gradu' and outputs 'gradv' and 322 'v', provided in that order, would result in an assembled QFunction that 323 consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting 324 on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v]. 325 326 @param op CeedOperator to assemble CeedQFunction 327 @param[out] assembled CeedVector to store assembled CeedQFunction at 328 quadrature points 329 @param[out] rstr CeedElemRestriction for CeedVector containing assembled 330 CeedQFunction 331 @param request Address of CeedRequest for non-blocking completion, else 332 CEED_REQUEST_IMMEDIATE 333 334 @return An error code: 0 - success, otherwise - failure 335 336 @ref Basic 337 **/ 338 int CeedOperatorAssembleLinearQFunction(CeedOperator op, CeedVector *assembled, 339 CeedElemRestriction *rstr, 340 CeedRequest *request) { 341 int ierr; 342 Ceed ceed = op->ceed; 343 CeedQFunction qf = op->qf; 344 345 if (op->composite) { 346 // LCOV_EXCL_START 347 return CeedError(ceed, 1, "Cannot assemble QFunction for composite operator"); 348 // LCOV_EXCL_STOP 349 } else { 350 if (op->nfields == 0) 351 // LCOV_EXCL_START 352 return CeedError(ceed, 1, "No operator fields set"); 353 // LCOV_EXCL_STOP 354 if (op->nfields < qf->numinputfields + qf->numoutputfields) 355 // LCOV_EXCL_START 356 return CeedError( ceed, 1, "Not all operator fields set"); 357 // LCOV_EXCL_STOP 358 if (!op->hasrestriction) 359 // LCOV_EXCL_START 360 return CeedError(ceed, 1, "At least one restriction required"); 361 // LCOV_EXCL_STOP 362 if (op->numqpoints == 0) 363 // LCOV_EXCL_START 364 return CeedError(ceed, 1, "At least one non-collocated basis required"); 365 // LCOV_EXCL_STOP 366 } 367 if (op->AssembleLinearQFunction) { 368 ierr = op->AssembleLinearQFunction(op, assembled, rstr, request); 369 CeedChk(ierr); 370 } else { 371 // Fallback to reference Ceed 372 if (!op->opfallback) { 373 ierr = CeedOperatorCreateFallback(op); CeedChk(ierr); 374 } 375 // Assemble 376 ierr = op->opfallback->AssembleLinearQFunction(op->opfallback, assembled, 377 rstr, request); CeedChk(ierr); 378 } 379 return 0; 380 } 381 382 /** 383 @brief Assemble the diagonal of a square linear Operator 384 385 This returns a CeedVector containing the diagonal of a linear CeedOperator. 386 387 @param op CeedOperator to assemble CeedQFunction 388 @param[out] assembled CeedVector to store assembled CeedOperator diagonal 389 @param request Address of CeedRequest for non-blocking completion, else 390 CEED_REQUEST_IMMEDIATE 391 392 @return An error code: 0 - success, otherwise - failure 393 394 @ref Basic 395 **/ 396 int CeedOperatorAssembleLinearDiagonal(CeedOperator op, CeedVector *assembled, 397 CeedRequest *request) { 398 int ierr; 399 Ceed ceed = op->ceed; 400 CeedQFunction qf = op->qf; 401 402 if (op->composite) { 403 // LCOV_EXCL_START 404 return CeedError(ceed, 1, "Cannot assemble QFunction for composite operator"); 405 // LCOV_EXCL_STOP 406 } else { 407 if (op->nfields == 0) 408 // LCOV_EXCL_START 409 return CeedError(ceed, 1, "No operator fields set"); 410 // LCOV_EXCL_STOP 411 if (op->nfields < qf->numinputfields + qf->numoutputfields) 412 // LCOV_EXCL_START 413 return CeedError( ceed, 1, "Not all operator fields set"); 414 // LCOV_EXCL_STOP 415 if (!op->hasrestriction) 416 // LCOV_EXCL_START 417 return CeedError(ceed, 1, "At least one restriction required"); 418 // LCOV_EXCL_STOP 419 if (op->numqpoints == 0) 420 // LCOV_EXCL_START 421 return CeedError(ceed, 1, "At least one non-collocated basis required"); 422 // LCOV_EXCL_STOP 423 } 424 425 // Use backend version, if available 426 if (op->AssembleLinearDiagonal) { 427 ierr = op->AssembleLinearDiagonal(op, assembled, request); CeedChk(ierr); 428 return 0; 429 } 430 431 // Assemble QFunction 432 CeedVector assembledqf; 433 CeedElemRestriction rstr; 434 ierr = CeedOperatorAssembleLinearQFunction(op, &assembledqf, &rstr, request); 435 CeedChk(ierr); 436 ierr = CeedElemRestrictionDestroy(&rstr); CeedChk(ierr); 437 438 // Determine active input basis 439 CeedInt numemodein = 0, ncomp, dim = 1; 440 CeedEvalMode *emodein = NULL; 441 CeedBasis basisin = NULL; 442 CeedElemRestriction rstrin = NULL; 443 for (CeedInt i=0; i<qf->numinputfields; i++) 444 if (op->inputfields[i]->vec == CEED_VECTOR_ACTIVE) { 445 ierr = CeedOperatorFieldGetBasis(op->inputfields[i], &basisin); 446 CeedChk(ierr); 447 ierr = CeedBasisGetNumComponents(basisin, &ncomp); CeedChk(ierr); 448 ierr = CeedBasisGetDimension(basisin, &dim); CeedChk(ierr); 449 ierr = CeedOperatorFieldGetElemRestriction(op->inputfields[i], &rstrin); 450 CeedChk(ierr); 451 CeedEvalMode emode; 452 ierr = CeedQFunctionFieldGetEvalMode(qf->inputfields[i], &emode); 453 CeedChk(ierr); 454 switch (emode) { 455 case CEED_EVAL_NONE: 456 case CEED_EVAL_INTERP: 457 ierr = CeedRealloc(numemodein + 1, &emodein); CeedChk(ierr); 458 emodein[numemodein] = emode; 459 numemodein += 1; 460 break; 461 case CEED_EVAL_GRAD: 462 ierr = CeedRealloc(numemodein + dim, &emodein); CeedChk(ierr); 463 for (CeedInt d=0; d<dim; d++) 464 emodein[numemodein+d] = emode; 465 numemodein += dim; 466 break; 467 case CEED_EVAL_WEIGHT: 468 case CEED_EVAL_DIV: 469 case CEED_EVAL_CURL: 470 break; // Caught by QF Assembly 471 } 472 } 473 474 // Determine active output basis 475 CeedInt numemodeout = 0; 476 CeedEvalMode *emodeout = NULL; 477 CeedBasis basisout = NULL; 478 CeedElemRestriction rstrout = NULL; 479 CeedTransposeMode lmodeout = CEED_NOTRANSPOSE; 480 for (CeedInt i=0; i<qf->numoutputfields; i++) 481 if (op->outputfields[i]->vec == CEED_VECTOR_ACTIVE) { 482 ierr = CeedOperatorFieldGetBasis(op->outputfields[i], &basisout); 483 CeedChk(ierr); 484 ierr = CeedOperatorFieldGetElemRestriction(op->outputfields[i], &rstrout); 485 CeedChk(ierr); 486 ierr = CeedOperatorFieldGetLMode(op->outputfields[i], &lmodeout); 487 CeedChk(ierr); 488 CeedEvalMode emode; 489 ierr = CeedQFunctionFieldGetEvalMode(qf->outputfields[i], &emode); 490 CeedChk(ierr); 491 switch (emode) { 492 case CEED_EVAL_NONE: 493 case CEED_EVAL_INTERP: 494 ierr = CeedRealloc(numemodeout + 1, &emodeout); CeedChk(ierr); 495 emodeout[numemodeout] = emode; 496 numemodeout += 1; 497 break; 498 case CEED_EVAL_GRAD: 499 ierr = CeedRealloc(numemodeout + dim, &emodeout); CeedChk(ierr); 500 for (CeedInt d=0; d<dim; d++) 501 emodeout[numemodeout+d] = emode; 502 numemodeout += dim; 503 break; 504 case CEED_EVAL_WEIGHT: 505 case CEED_EVAL_DIV: 506 case CEED_EVAL_CURL: 507 break; // Caught by QF Assembly 508 } 509 } 510 511 // Create diagonal vector 512 CeedVector elemdiag; 513 ierr = CeedElemRestrictionCreateVector(rstrin, assembled, &elemdiag); 514 CeedChk(ierr); 515 516 // Assemble element operator diagonals 517 CeedScalar *elemdiagarray, *assembledqfarray; 518 ierr = CeedVectorSetValue(elemdiag, 0.0); CeedChk(ierr); 519 ierr = CeedVectorGetArray(elemdiag, CEED_MEM_HOST, &elemdiagarray); 520 CeedChk(ierr); 521 ierr = CeedVectorGetArray(assembledqf, CEED_MEM_HOST, &assembledqfarray); 522 CeedChk(ierr); 523 CeedInt nelem, nnodes, nqpts; 524 ierr = CeedElemRestrictionGetNumElements(rstrin, &nelem); CeedChk(ierr); 525 ierr = CeedBasisGetNumNodes(basisin, &nnodes); CeedChk(ierr); 526 ierr = CeedBasisGetNumQuadraturePoints(basisin, &nqpts); CeedChk(ierr); 527 // Compute the diagonal of B^T D B 528 // Each node, qpt pair 529 for (CeedInt n=0; n<nnodes; n++) 530 for (CeedInt q=0; q<nqpts; q++) { 531 CeedInt dout = -1; 532 // Each basis eval mode pair 533 for (CeedInt eout=0; eout<numemodeout; eout++) { 534 CeedScalar bt = 1.0; 535 if (emodeout[eout] == CEED_EVAL_GRAD) 536 dout += 1; 537 ierr = CeedBasisGetValue(basisout, emodeout[eout], q, n, dout, &bt); 538 CeedChk(ierr); 539 CeedInt din = -1; 540 for (CeedInt ein=0; ein<numemodein; ein++) { 541 CeedScalar b = 0.0; 542 if (emodein[ein] == CEED_EVAL_GRAD) 543 din += 1; 544 ierr = CeedBasisGetValue(basisin, emodein[ein], q, n, din, &b); 545 CeedChk(ierr); 546 // Each element and component 547 for (CeedInt e=0; e<nelem; e++) 548 for (CeedInt cout=0; cout<ncomp; cout++) { 549 CeedScalar db = 0.0; 550 for (CeedInt cin=0; cin<ncomp; cin++) 551 db += assembledqfarray[((((e*numemodein+ein)*ncomp+cin)* 552 numemodeout+eout)*ncomp+cout)*nqpts+q]*b; 553 elemdiagarray[(e*ncomp+cout)*nnodes+n] += bt * db; 554 } 555 } 556 } 557 } 558 559 ierr = CeedVectorRestoreArray(elemdiag, &elemdiagarray); CeedChk(ierr); 560 ierr = CeedVectorRestoreArray(assembledqf, &assembledqfarray); CeedChk(ierr); 561 562 // Assemble local operator diagonal 563 ierr = CeedVectorSetValue(*assembled, 0.0); CeedChk(ierr); 564 ierr = CeedElemRestrictionApply(rstrout, CEED_TRANSPOSE, lmodeout, elemdiag, 565 *assembled, request); CeedChk(ierr); 566 567 // Cleanup 568 ierr = CeedVectorDestroy(&assembledqf); CeedChk(ierr); 569 ierr = CeedVectorDestroy(&elemdiag); CeedChk(ierr); 570 ierr = CeedFree(&emodein); CeedChk(ierr); 571 ierr = CeedFree(&emodeout); CeedChk(ierr); 572 573 return 0; 574 } 575 576 /** 577 @brief Apply CeedOperator to a vector and overwrite output vector 578 579 This computes the action of the operator on the specified (active) input, 580 yielding its (active) output. All inputs and outputs must be specified using 581 CeedOperatorSetField(). 582 583 @param op CeedOperator to apply 584 @param[in] in CeedVector containing input state or NULL if there are no 585 active inputs 586 @param[out] out CeedVector to store result of applying operator (must be 587 distinct from @a in) or NULL if there are no active outputs 588 @param request Address of CeedRequest for non-blocking completion, else 589 CEED_REQUEST_IMMEDIATE 590 591 @return An error code: 0 - success, otherwise - failure 592 593 @ref Basic 594 **/ 595 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, 596 CeedRequest *request) { 597 int ierr; 598 Ceed ceed = op->ceed; 599 CeedQFunction qf = op->qf; 600 601 if (op->composite) { 602 if (!op->numsub) 603 // LCOV_EXCL_START 604 return CeedError(ceed, 1, "No suboperators set"); 605 // LCOV_EXCL_STOP 606 } else { 607 if (op->nfields == 0) 608 // LCOV_EXCL_START 609 return CeedError(ceed, 1, "No operator fields set"); 610 // LCOV_EXCL_STOP 611 if (op->nfields < qf->numinputfields + qf->numoutputfields) 612 // LCOV_EXCL_START 613 return CeedError(ceed, 1, "Not all operator fields set"); 614 // LCOV_EXCL_STOP 615 if (!op->hasrestriction) 616 // LCOV_EXCL_START 617 return CeedError(ceed, 1,"At least one restriction required"); 618 // LCOV_EXCL_STOP 619 if (op->numqpoints == 0) 620 // LCOV_EXCL_START 621 return CeedError(ceed, 1,"At least one non-collocated basis required"); 622 // LCOV_EXCL_STOP 623 } 624 if (op->numelements || op->composite) { 625 if (op->Apply) { 626 ierr = op->Apply(op, in != CEED_VECTOR_NONE ? in : NULL, 627 out != CEED_VECTOR_NONE ? out : NULL, request); 628 CeedChk(ierr); 629 } else { 630 // Zero all output vectors 631 if (!op->composite) { 632 for (CeedInt i=0; i<qf->numoutputfields; i++) { 633 CeedVector vec = op->outputfields[i]->vec; 634 if (vec == CEED_VECTOR_ACTIVE) 635 vec = out; 636 if (vec != CEED_VECTOR_NONE) { 637 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 638 } 639 } 640 } else if (out != CEED_VECTOR_NONE) { // Zero active output if composite 641 ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr); 642 } 643 ierr = op->ApplyAdd(op, in != CEED_VECTOR_NONE ? in : NULL, 644 out != CEED_VECTOR_NONE ? out : NULL, request); 645 CeedChk(ierr); 646 } 647 } 648 return 0; 649 } 650 651 /** 652 @brief Apply CeedOperator to a vector and add result to output vector 653 654 This computes the action of the operator on the specified (active) input, 655 yielding its (active) output. All inputs and outputs must be specified using 656 CeedOperatorSetField(). 657 658 @param op CeedOperator to apply 659 @param[in] in CeedVector containing input state or NULL if there are no 660 active inputs 661 @param[out] out CeedVector to sum in result of applying operator (must be 662 distinct from @a in) or NULL if there are no active outputs 663 @param request Address of CeedRequest for non-blocking completion, else 664 CEED_REQUEST_IMMEDIATE 665 666 @return An error code: 0 - success, otherwise - failure 667 668 @ref Basic 669 **/ 670 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, 671 CeedRequest *request) { 672 int ierr; 673 Ceed ceed = op->ceed; 674 CeedQFunction qf = op->qf; 675 676 if (op->composite) { 677 if (!op->numsub) 678 // LCOV_EXCL_START 679 return CeedError(ceed, 1, "No suboperators set"); 680 // LCOV_EXCL_STOP 681 } else { 682 if (op->nfields == 0) 683 // LCOV_EXCL_START 684 return CeedError(ceed, 1, "No operator fields set"); 685 // LCOV_EXCL_STOP 686 if (op->nfields < qf->numinputfields + qf->numoutputfields) 687 // LCOV_EXCL_START 688 return CeedError(ceed, 1, "Not all operator fields set"); 689 // LCOV_EXCL_STOP 690 if (!op->hasrestriction) 691 // LCOV_EXCL_START 692 return CeedError(ceed, 1,"At least one restriction required"); 693 // LCOV_EXCL_STOP 694 if (op->numqpoints == 0) 695 // LCOV_EXCL_START 696 return CeedError(ceed, 1,"At least one non-collocated basis required"); 697 // LCOV_EXCL_STOP 698 } 699 if (op->numelements || op->composite) { 700 ierr = op->ApplyAdd(op, in != CEED_VECTOR_NONE ? in : NULL, 701 out != CEED_VECTOR_NONE ? out : NULL, request); 702 CeedChk(ierr); 703 } 704 return 0; 705 } 706 707 /** 708 @brief Get the Ceed associated with a CeedOperator 709 710 @param op CeedOperator 711 @param[out] ceed Variable to store Ceed 712 713 @return An error code: 0 - success, otherwise - failure 714 715 @ref Advanced 716 **/ 717 718 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) { 719 *ceed = op->ceed; 720 return 0; 721 } 722 723 /** 724 @brief Get the number of elements associated with a CeedOperator 725 726 @param op CeedOperator 727 @param[out] numelem Variable to store number of elements 728 729 @return An error code: 0 - success, otherwise - failure 730 731 @ref Advanced 732 **/ 733 734 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) { 735 if (op->composite) 736 // LCOV_EXCL_START 737 return CeedError(op->ceed, 1, "Not defined for composite operator"); 738 // LCOV_EXCL_STOP 739 740 *numelem = op->numelements; 741 return 0; 742 } 743 744 /** 745 @brief Get the number of quadrature points associated with a CeedOperator 746 747 @param op CeedOperator 748 @param[out] numqpts Variable to store vector number of quadrature points 749 750 @return An error code: 0 - success, otherwise - failure 751 752 @ref Advanced 753 **/ 754 755 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) { 756 if (op->composite) 757 // LCOV_EXCL_START 758 return CeedError(op->ceed, 1, "Not defined for composite operator"); 759 // LCOV_EXCL_STOP 760 761 *numqpts = op->numqpoints; 762 return 0; 763 } 764 765 /** 766 @brief Get the number of arguments associated with a CeedOperator 767 768 @param op CeedOperator 769 @param[out] numargs Variable to store vector number of arguments 770 771 @return An error code: 0 - success, otherwise - failure 772 773 @ref Advanced 774 **/ 775 776 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) { 777 if (op->composite) 778 // LCOV_EXCL_START 779 return CeedError(op->ceed, 1, "Not defined for composite operators"); 780 // LCOV_EXCL_STOP 781 782 *numargs = op->nfields; 783 return 0; 784 } 785 786 /** 787 @brief Get the setup status of a CeedOperator 788 789 @param op CeedOperator 790 @param[out] setupdone Variable to store setup status 791 792 @return An error code: 0 - success, otherwise - failure 793 794 @ref Advanced 795 **/ 796 797 int CeedOperatorGetSetupStatus(CeedOperator op, bool *setupdone) { 798 *setupdone = op->setupdone; 799 return 0; 800 } 801 802 /** 803 @brief Get the QFunction associated with a CeedOperator 804 805 @param op CeedOperator 806 @param[out] qf Variable to store QFunction 807 808 @return An error code: 0 - success, otherwise - failure 809 810 @ref Advanced 811 **/ 812 813 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) { 814 if (op->composite) 815 // LCOV_EXCL_START 816 return CeedError(op->ceed, 1, "Not defined for composite operator"); 817 // LCOV_EXCL_STOP 818 819 *qf = op->qf; 820 return 0; 821 } 822 823 /** 824 @brief Get the number of suboperators associated with a CeedOperator 825 826 @param op CeedOperator 827 @param[out] numsub Variable to store number of suboperators 828 829 @return An error code: 0 - success, otherwise - failure 830 831 @ref Advanced 832 **/ 833 834 int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) { 835 if (!op->composite) 836 // LCOV_EXCL_START 837 return CeedError(op->ceed, 1, "Not a composite operator"); 838 // LCOV_EXCL_STOP 839 840 *numsub = op->numsub; 841 return 0; 842 } 843 844 /** 845 @brief Get the list of suboperators associated with a CeedOperator 846 847 @param op CeedOperator 848 @param[out] suboperators Variable to store list of suboperators 849 850 @return An error code: 0 - success, otherwise - failure 851 852 @ref Advanced 853 **/ 854 855 int CeedOperatorGetSubList(CeedOperator op, CeedOperator **suboperators) { 856 if (!op->composite) 857 // LCOV_EXCL_START 858 return CeedError(op->ceed, 1, "Not a composite operator"); 859 // LCOV_EXCL_STOP 860 861 *suboperators = op->suboperators; 862 return 0; 863 } 864 865 /** 866 @brief Set the backend data of a CeedOperator 867 868 @param[out] op CeedOperator 869 @param data Data to set 870 871 @return An error code: 0 - success, otherwise - failure 872 873 @ref Advanced 874 **/ 875 876 int CeedOperatorSetData(CeedOperator op, void **data) { 877 op->data = *data; 878 return 0; 879 } 880 881 /** 882 @brief Get the backend data of a CeedOperator 883 884 @param op CeedOperator 885 @param[out] data Variable to store data 886 887 @return An error code: 0 - success, otherwise - failure 888 889 @ref Advanced 890 **/ 891 892 int CeedOperatorGetData(CeedOperator op, void **data) { 893 *data = op->data; 894 return 0; 895 } 896 897 /** 898 @brief Set the setup flag of a CeedOperator to True 899 900 @param op CeedOperator 901 902 @return An error code: 0 - success, otherwise - failure 903 904 @ref Advanced 905 **/ 906 907 int CeedOperatorSetSetupDone(CeedOperator op) { 908 op->setupdone = 1; 909 return 0; 910 } 911 912 /** 913 @brief View a field of a CeedOperator 914 915 @param[in] field Operator field to view 916 @param[in] fieldnumber Number of field being viewed 917 @param[in] stream Stream to view to, e.g., stdout 918 919 @return An error code: 0 - success, otherwise - failure 920 921 @ref Utility 922 **/ 923 static int CeedOperatorFieldView(CeedOperatorField field, 924 CeedQFunctionField qffield, 925 CeedInt fieldnumber, bool sub, bool in, 926 FILE *stream) { 927 const char *pre = sub ? " " : ""; 928 const char *inout = in ? "Input" : "Output"; 929 930 fprintf(stream, "%s %s Field [%d]:\n" 931 "%s Name: \"%s\"\n" 932 "%s Lmode: \"%s\"\n", 933 pre, inout, fieldnumber, pre, qffield->fieldname, 934 pre, CeedTransposeModes[field->lmode]); 935 936 if (field->basis == CEED_BASIS_COLLOCATED) 937 fprintf(stream, "%s Collocated basis\n", pre); 938 939 if (field->vec == CEED_VECTOR_ACTIVE) 940 fprintf(stream, "%s Active vector\n", pre); 941 else if (field->vec == CEED_VECTOR_NONE) 942 fprintf(stream, "%s No vector\n", pre); 943 944 return 0; 945 } 946 947 /** 948 @brief View a single CeedOperator 949 950 @param[in] op CeedOperator to view 951 @param[in] stream Stream to write; typically stdout/stderr or a file 952 953 @return Error code: 0 - success, otherwise - failure 954 955 @ref Utility 956 **/ 957 int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) { 958 int ierr; 959 const char *pre = sub ? " " : ""; 960 961 CeedInt totalfields; 962 ierr = CeedOperatorGetNumArgs(op, &totalfields); CeedChk(ierr); 963 964 fprintf(stream, "%s %d Field%s\n", pre, totalfields, totalfields>1 ? "s" : ""); 965 966 fprintf(stream, "%s %d Input Field%s:\n", pre, op->qf->numinputfields, 967 op->qf->numinputfields>1 ? "s" : ""); 968 for (CeedInt i=0; i<op->qf->numinputfields; i++) { 969 ierr = CeedOperatorFieldView(op->inputfields[i], op->qf->inputfields[i], 970 i, sub, 1, stream); CeedChk(ierr); 971 } 972 973 fprintf(stream, "%s %d Output Field%s:\n", pre, op->qf->numoutputfields, 974 op->qf->numoutputfields>1 ? "s" : ""); 975 for (CeedInt i=0; i<op->qf->numoutputfields; i++) { 976 ierr = CeedOperatorFieldView(op->outputfields[i], op->qf->inputfields[i], 977 i, sub, 0, stream); CeedChk(ierr); 978 } 979 980 return 0; 981 } 982 983 /** 984 @brief View a CeedOperator 985 986 @param[in] op CeedOperator to view 987 @param[in] stream Stream to write; typically stdout/stderr or a file 988 989 @return Error code: 0 - success, otherwise - failure 990 991 @ref Utility 992 **/ 993 int CeedOperatorView(CeedOperator op, FILE *stream) { 994 int ierr; 995 996 if (op->composite) { 997 fprintf(stream, "Composite CeedOperator\n"); 998 999 for (CeedInt i=0; i<op->numsub; i++) { 1000 fprintf(stream, " SubOperator [%d]:\n", i); 1001 ierr = CeedOperatorSingleView(op->suboperators[i], 1, stream); 1002 CeedChk(ierr); 1003 } 1004 } else { 1005 fprintf(stream, "CeedOperator\n"); 1006 ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr); 1007 } 1008 1009 return 0; 1010 } 1011 1012 /** 1013 @brief Get the CeedOperatorFields of a CeedOperator 1014 1015 @param op CeedOperator 1016 @param[out] inputfields Variable to store inputfields 1017 @param[out] outputfields Variable to store outputfields 1018 1019 @return An error code: 0 - success, otherwise - failure 1020 1021 @ref Advanced 1022 **/ 1023 1024 int CeedOperatorGetFields(CeedOperator op, CeedOperatorField **inputfields, 1025 CeedOperatorField **outputfields) { 1026 if (op->composite) 1027 // LCOV_EXCL_START 1028 return CeedError(op->ceed, 1, "Not defined for composite operator"); 1029 // LCOV_EXCL_STOP 1030 1031 if (inputfields) *inputfields = op->inputfields; 1032 if (outputfields) *outputfields = op->outputfields; 1033 return 0; 1034 } 1035 1036 /** 1037 @brief Get the L vector CeedTransposeMode of a CeedOperatorField 1038 1039 @param opfield CeedOperatorField 1040 @param[out] lmode Variable to store CeedTransposeMode 1041 1042 @return An error code: 0 - success, otherwise - failure 1043 1044 @ref Advanced 1045 **/ 1046 1047 int CeedOperatorFieldGetLMode(CeedOperatorField opfield, 1048 CeedTransposeMode *lmode) { 1049 *lmode = opfield->lmode; 1050 return 0; 1051 } 1052 1053 /** 1054 @brief Get the CeedElemRestriction of a CeedOperatorField 1055 1056 @param opfield CeedOperatorField 1057 @param[out] rstr Variable to store CeedElemRestriction 1058 1059 @return An error code: 0 - success, otherwise - failure 1060 1061 @ref Advanced 1062 **/ 1063 1064 int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield, 1065 CeedElemRestriction *rstr) { 1066 *rstr = opfield->Erestrict; 1067 return 0; 1068 } 1069 1070 /** 1071 @brief Get the CeedBasis of a CeedOperatorField 1072 1073 @param opfield CeedOperatorField 1074 @param[out] basis Variable to store CeedBasis 1075 1076 @return An error code: 0 - success, otherwise - failure 1077 1078 @ref Advanced 1079 **/ 1080 1081 int CeedOperatorFieldGetBasis(CeedOperatorField opfield, CeedBasis *basis) { 1082 *basis = opfield->basis; 1083 return 0; 1084 } 1085 1086 /** 1087 @brief Get the CeedVector of a CeedOperatorField 1088 1089 @param opfield CeedOperatorField 1090 @param[out] vec Variable to store CeedVector 1091 1092 @return An error code: 0 - success, otherwise - failure 1093 1094 @ref Advanced 1095 **/ 1096 1097 int CeedOperatorFieldGetVector(CeedOperatorField opfield, CeedVector *vec) { 1098 *vec = opfield->vec; 1099 return 0; 1100 } 1101 1102 /** 1103 @brief Destroy a CeedOperator 1104 1105 @param op CeedOperator to destroy 1106 1107 @return An error code: 0 - success, otherwise - failure 1108 1109 @ref Basic 1110 **/ 1111 int CeedOperatorDestroy(CeedOperator *op) { 1112 int ierr; 1113 1114 if (!*op || --(*op)->refcount > 0) return 0; 1115 if ((*op)->Destroy) { 1116 ierr = (*op)->Destroy(*op); CeedChk(ierr); 1117 } 1118 ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr); 1119 // Free fields 1120 for (int i=0; i<(*op)->nfields; i++) 1121 if ((*op)->inputfields[i]) { 1122 ierr = CeedElemRestrictionDestroy(&(*op)->inputfields[i]->Erestrict); 1123 CeedChk(ierr); 1124 if ((*op)->inputfields[i]->basis != CEED_BASIS_COLLOCATED) { 1125 ierr = CeedBasisDestroy(&(*op)->inputfields[i]->basis); CeedChk(ierr); 1126 } 1127 if ((*op)->inputfields[i]->vec != CEED_VECTOR_ACTIVE && 1128 (*op)->inputfields[i]->vec != CEED_VECTOR_NONE ) { 1129 ierr = CeedVectorDestroy(&(*op)->inputfields[i]->vec); CeedChk(ierr); 1130 } 1131 ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr); 1132 } 1133 for (int i=0; i<(*op)->nfields; i++) 1134 if ((*op)->outputfields[i]) { 1135 ierr = CeedElemRestrictionDestroy(&(*op)->outputfields[i]->Erestrict); 1136 CeedChk(ierr); 1137 if ((*op)->outputfields[i]->basis != CEED_BASIS_COLLOCATED) { 1138 ierr = CeedBasisDestroy(&(*op)->outputfields[i]->basis); CeedChk(ierr); 1139 } 1140 if ((*op)->outputfields[i]->vec != CEED_VECTOR_ACTIVE && 1141 (*op)->outputfields[i]->vec != CEED_VECTOR_NONE ) { 1142 ierr = CeedVectorDestroy(&(*op)->outputfields[i]->vec); CeedChk(ierr); 1143 } 1144 ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr); 1145 } 1146 // Destroy suboperators 1147 for (int i=0; i<(*op)->numsub; i++) 1148 if ((*op)->suboperators[i]) { 1149 ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr); 1150 } 1151 ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr); 1152 ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr); 1153 ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr); 1154 1155 // Destroy fallback 1156 if ((*op)->opfallback) { 1157 ierr = (*op)->qffallback->Destroy((*op)->qffallback); CeedChk(ierr); 1158 ierr = CeedFree(&(*op)->qffallback); CeedChk(ierr); 1159 ierr = (*op)->opfallback->Destroy((*op)->opfallback); CeedChk(ierr); 1160 ierr = CeedFree(&(*op)->opfallback); CeedChk(ierr); 1161 } 1162 1163 ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr); 1164 ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr); 1165 ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr); 1166 ierr = CeedFree(op); CeedChk(ierr); 1167 return 0; 1168 } 1169 1170 /// @} 1171