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