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