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 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 ierr = op->Apply(op, in != CEED_VECTOR_NONE ? in : NULL, 626 out != CEED_VECTOR_NONE ? out : NULL, request); 627 CeedChk(ierr); 628 } 629 return 0; 630 } 631 632 /** 633 @brief Get the Ceed associated with a CeedOperator 634 635 @param op CeedOperator 636 @param[out] ceed Variable to store Ceed 637 638 @return An error code: 0 - success, otherwise - failure 639 640 @ref Advanced 641 **/ 642 643 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) { 644 *ceed = op->ceed; 645 return 0; 646 } 647 648 /** 649 @brief Get the number of elements associated with a CeedOperator 650 651 @param op CeedOperator 652 @param[out] numelem Variable to store number of elements 653 654 @return An error code: 0 - success, otherwise - failure 655 656 @ref Advanced 657 **/ 658 659 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) { 660 if (op->composite) 661 // LCOV_EXCL_START 662 return CeedError(op->ceed, 1, "Not defined for composite operator"); 663 // LCOV_EXCL_STOP 664 665 *numelem = op->numelements; 666 return 0; 667 } 668 669 /** 670 @brief Get the number of quadrature points associated with a CeedOperator 671 672 @param op CeedOperator 673 @param[out] numqpts Variable to store vector number of quadrature points 674 675 @return An error code: 0 - success, otherwise - failure 676 677 @ref Advanced 678 **/ 679 680 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) { 681 if (op->composite) 682 // LCOV_EXCL_START 683 return CeedError(op->ceed, 1, "Not defined for composite operator"); 684 // LCOV_EXCL_STOP 685 686 *numqpts = op->numqpoints; 687 return 0; 688 } 689 690 /** 691 @brief Get the number of arguments associated with a CeedOperator 692 693 @param op CeedOperator 694 @param[out] numargs Variable to store vector number of arguments 695 696 @return An error code: 0 - success, otherwise - failure 697 698 @ref Advanced 699 **/ 700 701 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) { 702 if (op->composite) 703 // LCOV_EXCL_START 704 return CeedError(op->ceed, 1, "Not defined for composite operators"); 705 // LCOV_EXCL_STOP 706 707 *numargs = op->nfields; 708 return 0; 709 } 710 711 /** 712 @brief Get the setup status of a CeedOperator 713 714 @param op CeedOperator 715 @param[out] setupdone Variable to store setup status 716 717 @return An error code: 0 - success, otherwise - failure 718 719 @ref Advanced 720 **/ 721 722 int CeedOperatorGetSetupStatus(CeedOperator op, bool *setupdone) { 723 *setupdone = op->setupdone; 724 return 0; 725 } 726 727 /** 728 @brief Get the QFunction associated with a CeedOperator 729 730 @param op CeedOperator 731 @param[out] qf Variable to store QFunction 732 733 @return An error code: 0 - success, otherwise - failure 734 735 @ref Advanced 736 **/ 737 738 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) { 739 if (op->composite) 740 // LCOV_EXCL_START 741 return CeedError(op->ceed, 1, "Not defined for composite operator"); 742 // LCOV_EXCL_STOP 743 744 *qf = op->qf; 745 return 0; 746 } 747 748 /** 749 @brief Get the number of suboperators associated with a CeedOperator 750 751 @param op CeedOperator 752 @param[out] numsub Variable to store number of suboperators 753 754 @return An error code: 0 - success, otherwise - failure 755 756 @ref Advanced 757 **/ 758 759 int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) { 760 if (!op->composite) 761 // LCOV_EXCL_START 762 return CeedError(op->ceed, 1, "Not a composite operator"); 763 // LCOV_EXCL_STOP 764 765 *numsub = op->numsub; 766 return 0; 767 } 768 769 /** 770 @brief Get the list of suboperators associated with a CeedOperator 771 772 @param op CeedOperator 773 @param[out] suboperators Variable to store list of suboperators 774 775 @return An error code: 0 - success, otherwise - failure 776 777 @ref Advanced 778 **/ 779 780 int CeedOperatorGetSubList(CeedOperator op, CeedOperator **suboperators) { 781 if (!op->composite) 782 // LCOV_EXCL_START 783 return CeedError(op->ceed, 1, "Not a composite operator"); 784 // LCOV_EXCL_STOP 785 786 *suboperators = op->suboperators; 787 return 0; 788 } 789 790 /** 791 @brief Set the backend data of a CeedOperator 792 793 @param[out] op CeedOperator 794 @param data Data to set 795 796 @return An error code: 0 - success, otherwise - failure 797 798 @ref Advanced 799 **/ 800 801 int CeedOperatorSetData(CeedOperator op, void **data) { 802 op->data = *data; 803 return 0; 804 } 805 806 /** 807 @brief Get the backend data of a CeedOperator 808 809 @param op CeedOperator 810 @param[out] data Variable to store data 811 812 @return An error code: 0 - success, otherwise - failure 813 814 @ref Advanced 815 **/ 816 817 int CeedOperatorGetData(CeedOperator op, void **data) { 818 *data = op->data; 819 return 0; 820 } 821 822 /** 823 @brief Set the setup flag of a CeedOperator to True 824 825 @param op CeedOperator 826 827 @return An error code: 0 - success, otherwise - failure 828 829 @ref Advanced 830 **/ 831 832 int CeedOperatorSetSetupDone(CeedOperator op) { 833 op->setupdone = 1; 834 return 0; 835 } 836 837 /** 838 @brief View a field of a CeedOperator 839 840 @param[in] field Operator field to view 841 @param[in] fieldnumber Number of field being viewed 842 @param[in] stream Stream to view to, e.g., stdout 843 844 @return An error code: 0 - success, otherwise - failure 845 846 @ref Utility 847 **/ 848 static int CeedOperatorFieldView(CeedOperatorField field, 849 CeedQFunctionField qffield, 850 CeedInt fieldnumber, bool sub, bool in, 851 FILE *stream) { 852 const char *pre = sub ? " " : ""; 853 const char *inout = in ? "Input" : "Output"; 854 855 fprintf(stream, "%s %s Field [%d]:\n" 856 "%s Name: \"%s\"\n" 857 "%s Lmode: \"%s\"\n", 858 pre, inout, fieldnumber, pre, qffield->fieldname, 859 pre, CeedTransposeModes[field->lmode]); 860 861 if (field->basis == CEED_BASIS_COLLOCATED) 862 fprintf(stream, "%s Collocated basis\n", pre); 863 864 if (field->vec == CEED_VECTOR_ACTIVE) 865 fprintf(stream, "%s Active vector\n", pre); 866 else if (field->vec == CEED_VECTOR_NONE) 867 fprintf(stream, "%s No vector\n", pre); 868 869 return 0; 870 } 871 872 /** 873 @brief View a single CeedOperator 874 875 @param[in] op CeedOperator to view 876 @param[in] stream Stream to write; typically stdout/stderr or a file 877 878 @return Error code: 0 - success, otherwise - failure 879 880 @ref Utility 881 **/ 882 int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) { 883 int ierr; 884 const char *pre = sub ? " " : ""; 885 886 CeedInt totalfields; 887 ierr = CeedOperatorGetNumArgs(op, &totalfields); CeedChk(ierr); 888 889 fprintf(stream, "%s %d Field%s\n", pre, totalfields, totalfields>1 ? "s" : ""); 890 891 fprintf(stream, "%s %d Input Field%s:\n", pre, op->qf->numinputfields, 892 op->qf->numinputfields>1 ? "s" : ""); 893 for (CeedInt i=0; i<op->qf->numinputfields; i++) { 894 ierr = CeedOperatorFieldView(op->inputfields[i], op->qf->inputfields[i], 895 i, sub, 1, stream); CeedChk(ierr); 896 } 897 898 fprintf(stream, "%s %d Output Field%s:\n", pre, op->qf->numoutputfields, 899 op->qf->numoutputfields>1 ? "s" : ""); 900 for (CeedInt i=0; i<op->qf->numoutputfields; i++) { 901 ierr = CeedOperatorFieldView(op->outputfields[i], op->qf->inputfields[i], 902 i, sub, 0, stream); CeedChk(ierr); 903 } 904 905 return 0; 906 } 907 908 /** 909 @brief View a CeedOperator 910 911 @param[in] op CeedOperator to view 912 @param[in] stream Stream to write; typically stdout/stderr or a file 913 914 @return Error code: 0 - success, otherwise - failure 915 916 @ref Utility 917 **/ 918 int CeedOperatorView(CeedOperator op, FILE *stream) { 919 int ierr; 920 921 if (op->composite) { 922 fprintf(stream, "Composite CeedOperator\n"); 923 924 for (CeedInt i=0; i<op->numsub; i++) { 925 fprintf(stream, " SubOperator [%d]:\n", i); 926 ierr = CeedOperatorSingleView(op->suboperators[i], 1, stream); 927 CeedChk(ierr); 928 } 929 } else { 930 fprintf(stream, "CeedOperator\n"); 931 ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr); 932 } 933 934 return 0; 935 } 936 937 /** 938 @brief Get the CeedOperatorFields of a CeedOperator 939 940 @param op CeedOperator 941 @param[out] inputfields Variable to store inputfields 942 @param[out] outputfields Variable to store outputfields 943 944 @return An error code: 0 - success, otherwise - failure 945 946 @ref Advanced 947 **/ 948 949 int CeedOperatorGetFields(CeedOperator op, CeedOperatorField **inputfields, 950 CeedOperatorField **outputfields) { 951 if (op->composite) 952 // LCOV_EXCL_START 953 return CeedError(op->ceed, 1, "Not defined for composite operator"); 954 // LCOV_EXCL_STOP 955 956 if (inputfields) *inputfields = op->inputfields; 957 if (outputfields) *outputfields = op->outputfields; 958 return 0; 959 } 960 961 /** 962 @brief Get the L vector CeedTransposeMode of a CeedOperatorField 963 964 @param opfield CeedOperatorField 965 @param[out] lmode Variable to store CeedTransposeMode 966 967 @return An error code: 0 - success, otherwise - failure 968 969 @ref Advanced 970 **/ 971 972 int CeedOperatorFieldGetLMode(CeedOperatorField opfield, 973 CeedTransposeMode *lmode) { 974 *lmode = opfield->lmode; 975 return 0; 976 } 977 978 /** 979 @brief Get the CeedElemRestriction of a CeedOperatorField 980 981 @param opfield CeedOperatorField 982 @param[out] rstr Variable to store CeedElemRestriction 983 984 @return An error code: 0 - success, otherwise - failure 985 986 @ref Advanced 987 **/ 988 989 int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield, 990 CeedElemRestriction *rstr) { 991 *rstr = opfield->Erestrict; 992 return 0; 993 } 994 995 /** 996 @brief Get the CeedBasis of a CeedOperatorField 997 998 @param opfield CeedOperatorField 999 @param[out] basis Variable to store CeedBasis 1000 1001 @return An error code: 0 - success, otherwise - failure 1002 1003 @ref Advanced 1004 **/ 1005 1006 int CeedOperatorFieldGetBasis(CeedOperatorField opfield, CeedBasis *basis) { 1007 *basis = opfield->basis; 1008 return 0; 1009 } 1010 1011 /** 1012 @brief Get the CeedVector of a CeedOperatorField 1013 1014 @param opfield CeedOperatorField 1015 @param[out] vec Variable to store CeedVector 1016 1017 @return An error code: 0 - success, otherwise - failure 1018 1019 @ref Advanced 1020 **/ 1021 1022 int CeedOperatorFieldGetVector(CeedOperatorField opfield, CeedVector *vec) { 1023 *vec = opfield->vec; 1024 return 0; 1025 } 1026 1027 /** 1028 @brief Destroy a CeedOperator 1029 1030 @param op CeedOperator to destroy 1031 1032 @return An error code: 0 - success, otherwise - failure 1033 1034 @ref Basic 1035 **/ 1036 int CeedOperatorDestroy(CeedOperator *op) { 1037 int ierr; 1038 1039 if (!*op || --(*op)->refcount > 0) return 0; 1040 if ((*op)->Destroy) { 1041 ierr = (*op)->Destroy(*op); CeedChk(ierr); 1042 } 1043 ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr); 1044 // Free fields 1045 for (int i=0; i<(*op)->nfields; i++) 1046 if ((*op)->inputfields[i]) { 1047 ierr = CeedElemRestrictionDestroy(&(*op)->inputfields[i]->Erestrict); 1048 CeedChk(ierr); 1049 if ((*op)->inputfields[i]->basis != CEED_BASIS_COLLOCATED) { 1050 ierr = CeedBasisDestroy(&(*op)->inputfields[i]->basis); CeedChk(ierr); 1051 } 1052 if ((*op)->inputfields[i]->vec != CEED_VECTOR_ACTIVE && 1053 (*op)->inputfields[i]->vec != CEED_VECTOR_NONE ) { 1054 ierr = CeedVectorDestroy(&(*op)->inputfields[i]->vec); CeedChk(ierr); 1055 } 1056 ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr); 1057 } 1058 for (int i=0; i<(*op)->nfields; i++) 1059 if ((*op)->outputfields[i]) { 1060 ierr = CeedElemRestrictionDestroy(&(*op)->outputfields[i]->Erestrict); 1061 CeedChk(ierr); 1062 if ((*op)->outputfields[i]->basis != CEED_BASIS_COLLOCATED) { 1063 ierr = CeedBasisDestroy(&(*op)->outputfields[i]->basis); CeedChk(ierr); 1064 } 1065 if ((*op)->outputfields[i]->vec != CEED_VECTOR_ACTIVE && 1066 (*op)->outputfields[i]->vec != CEED_VECTOR_NONE ) { 1067 ierr = CeedVectorDestroy(&(*op)->outputfields[i]->vec); CeedChk(ierr); 1068 } 1069 ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr); 1070 } 1071 // Destroy suboperators 1072 for (int i=0; i<(*op)->numsub; i++) 1073 if ((*op)->suboperators[i]) { 1074 ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr); 1075 } 1076 ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr); 1077 ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr); 1078 ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr); 1079 1080 // Destroy fallback 1081 if ((*op)->opfallback) { 1082 ierr = (*op)->qffallback->Destroy((*op)->qffallback); CeedChk(ierr); 1083 ierr = CeedFree(&(*op)->qffallback); CeedChk(ierr); 1084 ierr = (*op)->opfallback->Destroy((*op)->opfallback); CeedChk(ierr); 1085 ierr = CeedFree(&(*op)->opfallback); CeedChk(ierr); 1086 } 1087 1088 ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr); 1089 ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr); 1090 ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr); 1091 ierr = CeedFree(op); CeedChk(ierr); 1092 return 0; 1093 } 1094 1095 /// @} 1096