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 #include <math.h> 21 22 /// @file 23 /// Implementation of public CeedOperator interfaces 24 /// 25 /// @addtogroup CeedOperator 26 /// @{ 27 28 /** 29 @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and 30 CeedElemRestriction can be associated with CeedQFunction fields with 31 \ref CeedOperatorSetField. 32 33 @param ceed A Ceed object where the CeedOperator will be created 34 @param qf QFunction defining the action of the operator at quadrature points 35 @param dqf QFunction defining the action of the Jacobian of @a qf (or 36 CEED_QFUNCTION_NONE) 37 @param dqfT QFunction defining the action of the transpose of the Jacobian 38 of @a qf (or CEED_QFUNCTION_NONE) 39 @param[out] op Address of the variable where the newly created 40 CeedOperator will be stored 41 42 @return An error code: 0 - success, otherwise - failure 43 44 @ref Basic 45 */ 46 int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, 47 CeedQFunction dqfT, CeedOperator *op) { 48 int ierr; 49 50 if (!ceed->OperatorCreate) { 51 Ceed delegate; 52 ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr); 53 54 if (!delegate) 55 // LCOV_EXCL_START 56 return CeedError(ceed, 1, "Backend does not support OperatorCreate"); 57 // LCOV_EXCL_STOP 58 59 ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr); 60 return 0; 61 } 62 63 ierr = CeedCalloc(1, op); CeedChk(ierr); 64 (*op)->ceed = ceed; 65 ceed->refcount++; 66 (*op)->refcount = 1; 67 if (qf == CEED_QFUNCTION_NONE) 68 // LCOV_EXCL_START 69 return CeedError(ceed, 1, "Operator must have a valid QFunction."); 70 // LCOV_EXCL_STOP 71 (*op)->qf = qf; 72 qf->refcount++; 73 if (dqf && dqf != CEED_QFUNCTION_NONE) { 74 (*op)->dqf = dqf; 75 dqf->refcount++; 76 } 77 if (dqfT && dqfT != CEED_QFUNCTION_NONE) { 78 (*op)->dqfT = dqfT; 79 dqfT->refcount++; 80 } 81 ierr = CeedCalloc(16, &(*op)->inputfields); CeedChk(ierr); 82 ierr = CeedCalloc(16, &(*op)->outputfields); CeedChk(ierr); 83 ierr = ceed->OperatorCreate(*op); CeedChk(ierr); 84 return 0; 85 } 86 87 /** 88 @brief Create an operator that composes the action of several operators 89 90 @param ceed A Ceed object where the CeedOperator will be created 91 @param[out] op Address of the variable where the newly created 92 Composite CeedOperator will be stored 93 94 @return An error code: 0 - success, otherwise - failure 95 96 @ref Basic 97 */ 98 int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) { 99 int ierr; 100 101 if (!ceed->CompositeOperatorCreate) { 102 Ceed delegate; 103 ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr); 104 105 if (delegate) { 106 ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr); 107 return 0; 108 } 109 } 110 111 ierr = CeedCalloc(1, op); CeedChk(ierr); 112 (*op)->ceed = ceed; 113 ceed->refcount++; 114 (*op)->composite = true; 115 ierr = CeedCalloc(16, &(*op)->suboperators); CeedChk(ierr); 116 117 if (ceed->CompositeOperatorCreate) { 118 ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr); 119 } 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 // Fallback Ceed 285 Ceed ceedref; 286 if (!op->ceed->opfallbackceed) { 287 ierr = CeedInit(fallbackresource, &ceedref); CeedChk(ierr); 288 ceedref->opfallbackparent = op->ceed; 289 op->ceed->opfallbackceed = ceedref; 290 } 291 ceedref = op->ceed->opfallbackceed; 292 293 // Clone Op 294 CeedOperator opref; 295 ierr = CeedCalloc(1, &opref); CeedChk(ierr); 296 memcpy(opref, op, sizeof(*opref)); CeedChk(ierr); 297 opref->data = NULL; 298 opref->setupdone = 0; 299 opref->ceed = ceedref; 300 ierr = ceedref->OperatorCreate(opref); CeedChk(ierr); 301 op->opfallback = opref; 302 303 // Clone QF 304 CeedQFunction qfref; 305 ierr = CeedCalloc(1, &qfref); CeedChk(ierr); 306 memcpy(qfref, (op->qf), sizeof(*qfref)); CeedChk(ierr); 307 qfref->data = NULL; 308 qfref->ceed = ceedref; 309 ierr = ceedref->QFunctionCreate(qfref); CeedChk(ierr); 310 opref->qf = qfref; 311 op->qffallback = qfref; 312 313 return 0; 314 } 315 316 /** 317 @brief Check if a CeedOperator is ready to be used. 318 319 @param[in] ceed Ceed object for error handling 320 @param[in] op CeedOperator to check 321 322 @return An error code: 0 - success, otherwise - failure 323 324 @ref Basic 325 **/ 326 static int CeedOperatorCheckReady(Ceed ceed, CeedOperator op) { 327 CeedQFunction qf = op->qf; 328 329 if (op->composite) { 330 if (!op->numsub) 331 // LCOV_EXCL_START 332 return CeedError(ceed, 1, "No suboperators set"); 333 // LCOV_EXCL_STOP 334 } else { 335 if (op->nfields == 0) 336 // LCOV_EXCL_START 337 return CeedError(ceed, 1, "No operator fields set"); 338 // LCOV_EXCL_STOP 339 if (op->nfields < qf->numinputfields + qf->numoutputfields) 340 // LCOV_EXCL_START 341 return CeedError(ceed, 1, "Not all operator fields set"); 342 // LCOV_EXCL_STOP 343 if (!op->hasrestriction) 344 // LCOV_EXCL_START 345 return CeedError(ceed, 1,"At least one restriction required"); 346 // LCOV_EXCL_STOP 347 if (op->numqpoints == 0) 348 // LCOV_EXCL_START 349 return CeedError(ceed, 1,"At least one non-collocated basis required"); 350 // LCOV_EXCL_STOP 351 } 352 353 return 0; 354 } 355 356 /** 357 @brief Assemble a linear CeedQFunction associated with a CeedOperator 358 359 This returns a CeedVector containing a matrix at each quadrature point 360 providing the action of the CeedQFunction associated with the CeedOperator. 361 The vector 'assembled' is of shape 362 [num_elements, num_input_fields, num_output_fields, num_quad_points] 363 and contains column-major matrices representing the action of the 364 CeedQFunction for a corresponding quadrature point on an element. Inputs and 365 outputs are in the order provided by the user when adding CeedOperator fields. 366 For example, a QFunction with inputs 'u' and 'gradu' and outputs 'gradv' and 367 'v', provided in that order, would result in an assembled QFunction that 368 consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting 369 on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v]. 370 371 @param op CeedOperator to assemble CeedQFunction 372 @param[out] assembled CeedVector to store assembled CeedQFunction at 373 quadrature points 374 @param[out] rstr CeedElemRestriction for CeedVector containing assembled 375 CeedQFunction 376 @param request Address of CeedRequest for non-blocking completion, else 377 CEED_REQUEST_IMMEDIATE 378 379 @return An error code: 0 - success, otherwise - failure 380 381 @ref Basic 382 **/ 383 int CeedOperatorAssembleLinearQFunction(CeedOperator op, CeedVector *assembled, 384 CeedElemRestriction *rstr, 385 CeedRequest *request) { 386 int ierr; 387 Ceed ceed = op->ceed; 388 ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr); 389 390 // Backend version 391 if (op->AssembleLinearQFunction) { 392 ierr = op->AssembleLinearQFunction(op, assembled, rstr, request); 393 CeedChk(ierr); 394 } else { 395 // Fallback to reference Ceed 396 if (!op->opfallback) { 397 ierr = CeedOperatorCreateFallback(op); CeedChk(ierr); 398 } 399 // Assemble 400 ierr = op->opfallback->AssembleLinearQFunction(op->opfallback, assembled, 401 rstr, request); CeedChk(ierr); 402 } 403 404 return 0; 405 } 406 407 /** 408 @brief Assemble the diagonal of a square linear Operator 409 410 This returns a CeedVector containing the diagonal of a linear CeedOperator. 411 412 @param op CeedOperator to assemble CeedQFunction 413 @param[out] assembled CeedVector to store assembled CeedOperator diagonal 414 @param request Address of CeedRequest for non-blocking completion, else 415 CEED_REQUEST_IMMEDIATE 416 417 @return An error code: 0 - success, otherwise - failure 418 419 @ref Basic 420 **/ 421 int CeedOperatorAssembleLinearDiagonal(CeedOperator op, CeedVector *assembled, 422 CeedRequest *request) { 423 int ierr; 424 Ceed ceed = op->ceed; 425 ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr); 426 427 // Use backend version, if available 428 if (op->AssembleLinearDiagonal) { 429 ierr = op->AssembleLinearDiagonal(op, assembled, request); CeedChk(ierr); 430 } else { 431 // Fallback to reference Ceed 432 if (!op->opfallback) { 433 ierr = CeedOperatorCreateFallback(op); CeedChk(ierr); 434 } 435 // Assemble 436 ierr = op->opfallback->AssembleLinearDiagonal(op->opfallback, assembled, 437 request); CeedChk(ierr); 438 } 439 440 return 0; 441 } 442 443 /** 444 @brief Build a FDM based approximate inverse for each element for a 445 CeedOperator 446 447 This returns a CeedOperator and CeedVector to apply a Fast Diagonalization 448 Method based approximate inverse. This function obtains the simultaneous 449 diagonalization for the 1D mass and Laplacian operators, 450 M = V^T V, K = V^T S V. 451 The assembled QFunction is used to modify the eigenvalues from simultaneous 452 diagonalization and obtain an approximate inverse of the form 453 V^T S^hat V. The CeedOperator must be linear and non-composite. The 454 associated CeedQFunction must therefore also be linear. 455 456 @param op CeedOperator to create element inverses 457 @param[out] fdminv CeedOperator to apply the action of a FDM based inverse 458 for each element 459 @param request Address of CeedRequest for non-blocking completion, else 460 CEED_REQUEST_IMMEDIATE 461 462 @return An error code: 0 - success, otherwise - failure 463 464 @ref Advanced 465 **/ 466 int CeedOperatorCreateFDMElementInverse(CeedOperator op, CeedOperator *fdminv, 467 CeedRequest *request) { 468 int ierr; 469 Ceed ceed = op->ceed; 470 ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr); 471 472 // Use backend version, if available 473 if (op->CreateFDMElementInverse) { 474 ierr = op->CreateFDMElementInverse(op, fdminv, request); CeedChk(ierr); 475 } else { 476 // Fallback to reference Ceed 477 if (!op->opfallback) { 478 ierr = CeedOperatorCreateFallback(op); CeedChk(ierr); 479 } 480 // Assemble 481 ierr = op->opfallback->CreateFDMElementInverse(op->opfallback, fdminv, 482 request); CeedChk(ierr); 483 } 484 485 return 0; 486 } 487 488 489 /** 490 @brief Apply CeedOperator to a vector 491 492 This computes the action of the operator on the specified (active) input, 493 yielding its (active) output. All inputs and outputs must be specified using 494 CeedOperatorSetField(). 495 496 @param op CeedOperator to apply 497 @param[in] in CeedVector containing input state or CEED_VECTOR_NONE if 498 there are no active inputs 499 @param[out] out CeedVector to store result of applying operator (must be 500 distinct from @a in) or CEED_VECTOR_NONE if there are no 501 active outputs 502 @param request Address of CeedRequest for non-blocking completion, else 503 CEED_REQUEST_IMMEDIATE 504 505 @return An error code: 0 - success, otherwise - failure 506 507 @ref Basic 508 **/ 509 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, 510 CeedRequest *request) { 511 int ierr; 512 Ceed ceed = op->ceed; 513 ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr); 514 515 if (op->numelements) { 516 // Standard Operator 517 if (op->Apply) { 518 ierr = op->Apply(op, in, out, request); CeedChk(ierr); 519 } else { 520 // Zero all output vectors 521 CeedQFunction qf = op->qf; 522 for (CeedInt i=0; i<qf->numoutputfields; i++) { 523 CeedVector vec = op->outputfields[i]->vec; 524 if (vec == CEED_VECTOR_ACTIVE) 525 vec = out; 526 if (vec != CEED_VECTOR_NONE) { 527 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 528 } 529 } 530 // Apply 531 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 532 } 533 } else if (op->composite) { 534 // Composite Operator 535 if (op->ApplyComposite) { 536 ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr); 537 } else { 538 CeedInt numsub; 539 ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr); 540 CeedOperator *suboperators; 541 ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr); 542 543 // Zero all output vectors 544 if (out != CEED_VECTOR_NONE) { 545 ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr); 546 } 547 for (CeedInt i=0; i<numsub; i++) { 548 for (CeedInt j=0; j<suboperators[i]->qf->numoutputfields; j++) { 549 CeedVector vec = suboperators[i]->outputfields[j]->vec; 550 if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) { 551 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 552 } 553 } 554 } 555 // Apply 556 for (CeedInt i=0; i<op->numsub; i++) { 557 ierr = CeedOperatorApplyAdd(op->suboperators[i], in, out, request); 558 CeedChk(ierr); 559 } 560 } 561 } 562 563 return 0; 564 } 565 566 /** 567 @brief Apply CeedOperator to a vector and add result to output vector 568 569 This computes the action of the operator on the specified (active) input, 570 yielding its (active) output. All inputs and outputs must be specified using 571 CeedOperatorSetField(). 572 573 @param op CeedOperator to apply 574 @param[in] in CeedVector containing input state or NULL if there are no 575 active inputs 576 @param[out] out CeedVector to sum in result of applying operator (must be 577 distinct from @a in) or NULL if there are no active outputs 578 @param request Address of CeedRequest for non-blocking completion, else 579 CEED_REQUEST_IMMEDIATE 580 581 @return An error code: 0 - success, otherwise - failure 582 583 @ref Basic 584 **/ 585 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, 586 CeedRequest *request) { 587 int ierr; 588 Ceed ceed = op->ceed; 589 ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr); 590 591 if (op->numelements) { 592 // Standard Operator 593 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 594 } else if (op->composite) { 595 // Composite Operator 596 if (op->ApplyAddComposite) { 597 ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr); 598 } else { 599 CeedInt numsub; 600 ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr); 601 CeedOperator *suboperators; 602 ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr); 603 604 for (CeedInt i=0; i<numsub; i++) { 605 ierr = CeedOperatorApplyAdd(suboperators[i], in, out, request); 606 CeedChk(ierr); 607 } 608 } 609 } 610 611 return 0; 612 } 613 614 /** 615 @brief Get the Ceed associated with a CeedOperator 616 617 @param op CeedOperator 618 @param[out] ceed Variable to store Ceed 619 620 @return An error code: 0 - success, otherwise - failure 621 622 @ref Advanced 623 **/ 624 625 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) { 626 *ceed = op->ceed; 627 return 0; 628 } 629 630 /** 631 @brief Get the number of elements associated with a CeedOperator 632 633 @param op CeedOperator 634 @param[out] numelem Variable to store number of elements 635 636 @return An error code: 0 - success, otherwise - failure 637 638 @ref Advanced 639 **/ 640 641 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) { 642 if (op->composite) 643 // LCOV_EXCL_START 644 return CeedError(op->ceed, 1, "Not defined for composite operator"); 645 // LCOV_EXCL_STOP 646 647 *numelem = op->numelements; 648 return 0; 649 } 650 651 /** 652 @brief Get the number of quadrature points associated with a CeedOperator 653 654 @param op CeedOperator 655 @param[out] numqpts Variable to store vector number of quadrature points 656 657 @return An error code: 0 - success, otherwise - failure 658 659 @ref Advanced 660 **/ 661 662 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) { 663 if (op->composite) 664 // LCOV_EXCL_START 665 return CeedError(op->ceed, 1, "Not defined for composite operator"); 666 // LCOV_EXCL_STOP 667 668 *numqpts = op->numqpoints; 669 return 0; 670 } 671 672 /** 673 @brief Get the number of arguments associated with a CeedOperator 674 675 @param op CeedOperator 676 @param[out] numargs Variable to store vector number of arguments 677 678 @return An error code: 0 - success, otherwise - failure 679 680 @ref Advanced 681 **/ 682 683 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) { 684 if (op->composite) 685 // LCOV_EXCL_START 686 return CeedError(op->ceed, 1, "Not defined for composite operators"); 687 // LCOV_EXCL_STOP 688 689 *numargs = op->nfields; 690 return 0; 691 } 692 693 /** 694 @brief Get the setup status of a CeedOperator 695 696 @param op CeedOperator 697 @param[out] setupdone Variable to store setup status 698 699 @return An error code: 0 - success, otherwise - failure 700 701 @ref Advanced 702 **/ 703 704 int CeedOperatorGetSetupStatus(CeedOperator op, bool *setupdone) { 705 *setupdone = op->setupdone; 706 return 0; 707 } 708 709 /** 710 @brief Get the QFunction associated with a CeedOperator 711 712 @param op CeedOperator 713 @param[out] qf Variable to store QFunction 714 715 @return An error code: 0 - success, otherwise - failure 716 717 @ref Advanced 718 **/ 719 720 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) { 721 if (op->composite) 722 // LCOV_EXCL_START 723 return CeedError(op->ceed, 1, "Not defined for composite operator"); 724 // LCOV_EXCL_STOP 725 726 *qf = op->qf; 727 return 0; 728 } 729 730 /** 731 @brief Get the number of suboperators associated with a CeedOperator 732 733 @param op CeedOperator 734 @param[out] numsub Variable to store number of suboperators 735 736 @return An error code: 0 - success, otherwise - failure 737 738 @ref Advanced 739 **/ 740 741 int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) { 742 if (!op->composite) 743 // LCOV_EXCL_START 744 return CeedError(op->ceed, 1, "Not a composite operator"); 745 // LCOV_EXCL_STOP 746 747 *numsub = op->numsub; 748 return 0; 749 } 750 751 /** 752 @brief Get the list of suboperators associated with a CeedOperator 753 754 @param op CeedOperator 755 @param[out] suboperators Variable to store list of suboperators 756 757 @return An error code: 0 - success, otherwise - failure 758 759 @ref Advanced 760 **/ 761 762 int CeedOperatorGetSubList(CeedOperator op, CeedOperator **suboperators) { 763 if (!op->composite) 764 // LCOV_EXCL_START 765 return CeedError(op->ceed, 1, "Not a composite operator"); 766 // LCOV_EXCL_STOP 767 768 *suboperators = op->suboperators; 769 return 0; 770 } 771 772 /** 773 @brief Set the backend data of a CeedOperator 774 775 @param[out] op CeedOperator 776 @param data Data to set 777 778 @return An error code: 0 - success, otherwise - failure 779 780 @ref Advanced 781 **/ 782 783 int CeedOperatorSetData(CeedOperator op, void **data) { 784 op->data = *data; 785 return 0; 786 } 787 788 /** 789 @brief Get the backend data of a CeedOperator 790 791 @param op CeedOperator 792 @param[out] data Variable to store data 793 794 @return An error code: 0 - success, otherwise - failure 795 796 @ref Advanced 797 **/ 798 799 int CeedOperatorGetData(CeedOperator op, void **data) { 800 *data = op->data; 801 return 0; 802 } 803 804 /** 805 @brief Set the setup flag of a CeedOperator to True 806 807 @param op CeedOperator 808 809 @return An error code: 0 - success, otherwise - failure 810 811 @ref Advanced 812 **/ 813 814 int CeedOperatorSetSetupDone(CeedOperator op) { 815 op->setupdone = 1; 816 return 0; 817 } 818 819 /** 820 @brief View a field of a CeedOperator 821 822 @param[in] field Operator field to view 823 @param[in] fieldnumber Number of field being viewed 824 @param[in] stream Stream to view to, e.g., stdout 825 826 @return An error code: 0 - success, otherwise - failure 827 828 @ref Utility 829 **/ 830 static int CeedOperatorFieldView(CeedOperatorField field, 831 CeedQFunctionField qffield, 832 CeedInt fieldnumber, bool sub, bool in, 833 FILE *stream) { 834 const char *pre = sub ? " " : ""; 835 const char *inout = in ? "Input" : "Output"; 836 837 fprintf(stream, "%s %s Field [%d]:\n" 838 "%s Name: \"%s\"\n" 839 "%s Lmode: \"%s\"\n", 840 pre, inout, fieldnumber, pre, qffield->fieldname, 841 pre, CeedTransposeModes[field->lmode]); 842 843 if (field->basis == CEED_BASIS_COLLOCATED) 844 fprintf(stream, "%s Collocated basis\n", pre); 845 846 if (field->vec == CEED_VECTOR_ACTIVE) 847 fprintf(stream, "%s Active vector\n", pre); 848 else if (field->vec == CEED_VECTOR_NONE) 849 fprintf(stream, "%s No vector\n", pre); 850 851 return 0; 852 } 853 854 /** 855 @brief View a single CeedOperator 856 857 @param[in] op CeedOperator to view 858 @param[in] sub Boolean flag for sub-operator 859 @param[in] stream Stream to write; typically stdout/stderr or a file 860 861 @return Error code: 0 - success, otherwise - failure 862 863 @ref Utility 864 **/ 865 int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) { 866 int ierr; 867 const char *pre = sub ? " " : ""; 868 869 CeedInt totalfields; 870 ierr = CeedOperatorGetNumArgs(op, &totalfields); CeedChk(ierr); 871 872 fprintf(stream, "%s %d Field%s\n", pre, totalfields, totalfields>1 ? "s" : ""); 873 874 fprintf(stream, "%s %d Input Field%s:\n", pre, op->qf->numinputfields, 875 op->qf->numinputfields>1 ? "s" : ""); 876 for (CeedInt i=0; i<op->qf->numinputfields; i++) { 877 ierr = CeedOperatorFieldView(op->inputfields[i], op->qf->inputfields[i], 878 i, sub, 1, stream); CeedChk(ierr); 879 } 880 881 fprintf(stream, "%s %d Output Field%s:\n", pre, op->qf->numoutputfields, 882 op->qf->numoutputfields>1 ? "s" : ""); 883 for (CeedInt i=0; i<op->qf->numoutputfields; i++) { 884 ierr = CeedOperatorFieldView(op->outputfields[i], op->qf->inputfields[i], 885 i, sub, 0, stream); CeedChk(ierr); 886 } 887 888 return 0; 889 } 890 891 /** 892 @brief View a CeedOperator 893 894 @param[in] op CeedOperator to view 895 @param[in] stream Stream to write; typically stdout/stderr or a file 896 897 @return Error code: 0 - success, otherwise - failure 898 899 @ref Utility 900 **/ 901 int CeedOperatorView(CeedOperator op, FILE *stream) { 902 int ierr; 903 904 if (op->composite) { 905 fprintf(stream, "Composite CeedOperator\n"); 906 907 for (CeedInt i=0; i<op->numsub; i++) { 908 fprintf(stream, " SubOperator [%d]:\n", i); 909 ierr = CeedOperatorSingleView(op->suboperators[i], 1, stream); 910 CeedChk(ierr); 911 } 912 } else { 913 fprintf(stream, "CeedOperator\n"); 914 ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr); 915 } 916 917 return 0; 918 } 919 920 /** 921 @brief Get the CeedOperatorFields of a CeedOperator 922 923 @param op CeedOperator 924 @param[out] inputfields Variable to store inputfields 925 @param[out] outputfields Variable to store outputfields 926 927 @return An error code: 0 - success, otherwise - failure 928 929 @ref Advanced 930 **/ 931 932 int CeedOperatorGetFields(CeedOperator op, CeedOperatorField **inputfields, 933 CeedOperatorField **outputfields) { 934 if (op->composite) 935 // LCOV_EXCL_START 936 return CeedError(op->ceed, 1, "Not defined for composite operator"); 937 // LCOV_EXCL_STOP 938 939 if (inputfields) *inputfields = op->inputfields; 940 if (outputfields) *outputfields = op->outputfields; 941 return 0; 942 } 943 944 /** 945 @brief Get the L vector CeedTransposeMode of a CeedOperatorField 946 947 @param opfield CeedOperatorField 948 @param[out] lmode Variable to store CeedTransposeMode 949 950 @return An error code: 0 - success, otherwise - failure 951 952 @ref Advanced 953 **/ 954 955 int CeedOperatorFieldGetLMode(CeedOperatorField opfield, 956 CeedTransposeMode *lmode) { 957 *lmode = opfield->lmode; 958 return 0; 959 } 960 961 /** 962 @brief Get the CeedElemRestriction of a CeedOperatorField 963 964 @param opfield CeedOperatorField 965 @param[out] rstr Variable to store CeedElemRestriction 966 967 @return An error code: 0 - success, otherwise - failure 968 969 @ref Advanced 970 **/ 971 972 int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield, 973 CeedElemRestriction *rstr) { 974 *rstr = opfield->Erestrict; 975 return 0; 976 } 977 978 /** 979 @brief Get the CeedBasis of a CeedOperatorField 980 981 @param opfield CeedOperatorField 982 @param[out] basis Variable to store CeedBasis 983 984 @return An error code: 0 - success, otherwise - failure 985 986 @ref Advanced 987 **/ 988 989 int CeedOperatorFieldGetBasis(CeedOperatorField opfield, CeedBasis *basis) { 990 *basis = opfield->basis; 991 return 0; 992 } 993 994 /** 995 @brief Get the CeedVector of a CeedOperatorField 996 997 @param opfield CeedOperatorField 998 @param[out] vec Variable to store CeedVector 999 1000 @return An error code: 0 - success, otherwise - failure 1001 1002 @ref Advanced 1003 **/ 1004 1005 int CeedOperatorFieldGetVector(CeedOperatorField opfield, CeedVector *vec) { 1006 *vec = opfield->vec; 1007 return 0; 1008 } 1009 1010 /** 1011 @brief Destroy a CeedOperator 1012 1013 @param op CeedOperator to destroy 1014 1015 @return An error code: 0 - success, otherwise - failure 1016 1017 @ref Basic 1018 **/ 1019 int CeedOperatorDestroy(CeedOperator *op) { 1020 int ierr; 1021 1022 if (!*op || --(*op)->refcount > 0) return 0; 1023 if ((*op)->Destroy) { 1024 ierr = (*op)->Destroy(*op); CeedChk(ierr); 1025 } 1026 ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr); 1027 // Free fields 1028 for (int i=0; i<(*op)->nfields; i++) 1029 if ((*op)->inputfields[i]) { 1030 ierr = CeedElemRestrictionDestroy(&(*op)->inputfields[i]->Erestrict); 1031 CeedChk(ierr); 1032 if ((*op)->inputfields[i]->basis != CEED_BASIS_COLLOCATED) { 1033 ierr = CeedBasisDestroy(&(*op)->inputfields[i]->basis); CeedChk(ierr); 1034 } 1035 if ((*op)->inputfields[i]->vec != CEED_VECTOR_ACTIVE && 1036 (*op)->inputfields[i]->vec != CEED_VECTOR_NONE ) { 1037 ierr = CeedVectorDestroy(&(*op)->inputfields[i]->vec); CeedChk(ierr); 1038 } 1039 ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr); 1040 } 1041 for (int i=0; i<(*op)->nfields; i++) 1042 if ((*op)->outputfields[i]) { 1043 ierr = CeedElemRestrictionDestroy(&(*op)->outputfields[i]->Erestrict); 1044 CeedChk(ierr); 1045 if ((*op)->outputfields[i]->basis != CEED_BASIS_COLLOCATED) { 1046 ierr = CeedBasisDestroy(&(*op)->outputfields[i]->basis); CeedChk(ierr); 1047 } 1048 if ((*op)->outputfields[i]->vec != CEED_VECTOR_ACTIVE && 1049 (*op)->outputfields[i]->vec != CEED_VECTOR_NONE ) { 1050 ierr = CeedVectorDestroy(&(*op)->outputfields[i]->vec); CeedChk(ierr); 1051 } 1052 ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr); 1053 } 1054 // Destroy suboperators 1055 for (int i=0; i<(*op)->numsub; i++) 1056 if ((*op)->suboperators[i]) { 1057 ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr); 1058 } 1059 ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr); 1060 ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr); 1061 ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr); 1062 1063 // Destroy fallback 1064 if ((*op)->opfallback) { 1065 ierr = (*op)->qffallback->Destroy((*op)->qffallback); CeedChk(ierr); 1066 ierr = CeedFree(&(*op)->qffallback); CeedChk(ierr); 1067 ierr = (*op)->opfallback->Destroy((*op)->opfallback); CeedChk(ierr); 1068 ierr = CeedFree(&(*op)->opfallback); CeedChk(ierr); 1069 } 1070 1071 ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr); 1072 ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr); 1073 ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr); 1074 ierr = CeedFree(op); CeedChk(ierr); 1075 return 0; 1076 } 1077 1078 /// @} 1079