1 // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at 2 // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights 3 // reserved. See files LICENSE and NOTICE for details. 4 // 5 // This file is part of CEED, a collection of benchmarks, miniapps, software 6 // libraries and APIs for efficient high-order finite element and spectral 7 // element discretizations for exascale applications. For more information and 8 // source code availability see http://github.com/ceed. 9 // 10 // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC, 11 // a collaborative effort of two U.S. Department of Energy organizations (Office 12 // of Science and the National Nuclear Security Administration) responsible for 13 // the planning and preparation of a capable exascale ecosystem, including 14 // software, applications, hardware, advanced system engineering and early 15 // testbed platforms, in support of the nation's exascale computing imperative. 16 17 #include <ceed-impl.h> 18 #include <ceed-backend.h> 19 #include <string.h> 20 21 /// @file 22 /// Implementation of public CeedOperator interfaces 23 /// 24 /// @addtogroup CeedOperator 25 /// @{ 26 27 /** 28 @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and 29 CeedElemRestriction can be associated with CeedQFunction fields with 30 \ref CeedOperatorSetField. 31 32 @param ceed A Ceed object where the CeedOperator will be created 33 @param qf QFunction defining the action of the operator at quadrature points 34 @param dqf QFunction defining the action of the Jacobian of @a qf (or NULL) 35 @param dqfT QFunction defining the action of the transpose of the Jacobian 36 of @a qf (or NULL) 37 @param[out] op Address of the variable where the newly created 38 CeedOperator will be stored 39 40 @return An error code: 0 - success, otherwise - failure 41 42 @ref Basic 43 */ 44 int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, 45 CeedQFunction dqfT, CeedOperator *op) { 46 int ierr; 47 48 if (!ceed->OperatorCreate) { 49 Ceed delegate; 50 ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr); 51 52 if (!delegate) 53 // LCOV_EXCL_START 54 return CeedError(ceed, 1, "Backend does not support OperatorCreate"); 55 // LCOV_EXCL_STOP 56 57 ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr); 58 return 0; 59 } 60 61 ierr = CeedCalloc(1,op); CeedChk(ierr); 62 (*op)->ceed = ceed; 63 ceed->refcount++; 64 (*op)->refcount = 1; 65 (*op)->qf = qf; 66 qf->refcount++; 67 (*op)->dqf = dqf; 68 if (dqf) dqf->refcount++; 69 (*op)->dqfT = dqfT; 70 if (dqfT) dqfT->refcount++; 71 ierr = CeedCalloc(16, &(*op)->inputfields); CeedChk(ierr); 72 ierr = CeedCalloc(16, &(*op)->outputfields); CeedChk(ierr); 73 ierr = ceed->OperatorCreate(*op); CeedChk(ierr); 74 return 0; 75 } 76 77 /** 78 @brief Create an operator that composes the action of several operators 79 80 @param ceed A Ceed object where the CeedOperator will be created 81 @param[out] op Address of the variable where the newly created 82 Composite CeedOperator will be stored 83 84 @return An error code: 0 - success, otherwise - failure 85 86 @ref Basic 87 */ 88 int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) { 89 int ierr; 90 91 if (!ceed->CompositeOperatorCreate) { 92 Ceed delegate; 93 ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr); 94 95 if (!delegate) 96 // LCOV_EXCL_START 97 return CeedError(ceed, 1, "Backend does not support " 98 "CompositeOperatorCreate"); 99 // LCOV_EXCL_STOP 100 101 ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr); 102 return 0; 103 } 104 105 ierr = CeedCalloc(1,op); CeedChk(ierr); 106 (*op)->ceed = ceed; 107 ceed->refcount++; 108 (*op)->composite = true; 109 ierr = CeedCalloc(16, &(*op)->suboperators); CeedChk(ierr); 110 ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr); 111 return 0; 112 } 113 114 /** 115 @brief Provide a field to a CeedOperator for use by its CeedQFunction 116 117 This function is used to specify both active and passive fields to a 118 CeedOperator. For passive fields, a vector @arg v must be provided. Passive 119 fields can inputs or outputs (updated in-place when operator is applied). 120 121 Active fields must be specified using this function, but their data (in a 122 CeedVector) is passed in CeedOperatorApply(). There can be at most one active 123 input and at most one active output. 124 125 @param op CeedOperator on which to provide the field 126 @param fieldname Name of the field (to be matched with the name used by 127 CeedQFunction) 128 @param r CeedElemRestriction 129 @param lmode CeedTransposeMode which specifies the ordering of the 130 components of the l-vector used by this CeedOperatorField, 131 CEED_NOTRANSPOSE indicates the component is the 132 outermost index and CEED_TRANSPOSE indicates the component 133 is the innermost index in ordering of the l-vector 134 @param b CeedBasis in which the field resides or CEED_BASIS_COLLOCATED 135 if collocated with quadrature points 136 @param v CeedVector to be used by CeedOperator or CEED_VECTOR_ACTIVE 137 if field is active or CEED_VECTOR_NONE if using 138 CEED_EVAL_WEIGHT in the QFunction 139 140 @return An error code: 0 - success, otherwise - failure 141 142 @ref Basic 143 **/ 144 int CeedOperatorSetField(CeedOperator op, const char *fieldname, 145 CeedElemRestriction r, CeedTransposeMode lmode, 146 CeedBasis b, CeedVector v) { 147 int ierr; 148 if (op->composite) 149 // LCOV_EXCL_START 150 return CeedError(op->ceed, 1, "Cannot add field to composite operator."); 151 // LCOV_EXCL_STOP 152 if (!r) 153 // LCOV_EXCL_START 154 return CeedError(op->ceed, 1, 155 "ElemRestriction r for field \"%s\" must be non-NULL.", 156 fieldname); 157 // LCOV_EXCL_STOP 158 if (!b) 159 // LCOV_EXCL_START 160 return CeedError(op->ceed, 1, "Basis b for field \"%s\" must be non-NULL.", 161 fieldname); 162 // LCOV_EXCL_STOP 163 if (!v) 164 // LCOV_EXCL_START 165 return CeedError(op->ceed, 1, "Vector v for field \"%s\" must be non-NULL.", 166 fieldname); 167 // LCOV_EXCL_STOP 168 169 CeedInt numelements; 170 ierr = CeedElemRestrictionGetNumElements(r, &numelements); CeedChk(ierr); 171 if (op->numelements && op->numelements != numelements) 172 // LCOV_EXCL_START 173 return CeedError(op->ceed, 1, 174 "ElemRestriction with %d elements incompatible with prior " 175 "%d elements", numelements, op->numelements); 176 // LCOV_EXCL_STOP 177 op->numelements = numelements; 178 179 if (b != CEED_BASIS_COLLOCATED) { 180 CeedInt numqpoints; 181 ierr = CeedBasisGetNumQuadraturePoints(b, &numqpoints); CeedChk(ierr); 182 if (op->numqpoints && op->numqpoints != numqpoints) 183 // LCOV_EXCL_START 184 return CeedError(op->ceed, 1, "Basis with %d quadrature points " 185 "incompatible with prior %d points", numqpoints, 186 op->numqpoints); 187 // LCOV_EXCL_STOP 188 op->numqpoints = numqpoints; 189 } 190 CeedOperatorField *ofield; 191 for (CeedInt i=0; i<op->qf->numinputfields; i++) { 192 if (!strcmp(fieldname, (*op->qf->inputfields[i]).fieldname)) { 193 ofield = &op->inputfields[i]; 194 goto found; 195 } 196 } 197 for (CeedInt i=0; i<op->qf->numoutputfields; i++) { 198 if (!strcmp(fieldname, (*op->qf->outputfields[i]).fieldname)) { 199 ofield = &op->outputfields[i]; 200 goto found; 201 } 202 } 203 // LCOV_EXCL_START 204 return CeedError(op->ceed, 1, "QFunction has no knowledge of field '%s'", 205 fieldname); 206 // LCOV_EXCL_STOP 207 found: 208 ierr = CeedCalloc(1, ofield); CeedChk(ierr); 209 (*ofield)->Erestrict = r; 210 r->refcount += 1; 211 (*ofield)->lmode = lmode; 212 (*ofield)->basis = b; 213 if (b != CEED_BASIS_COLLOCATED) 214 b->refcount += 1; 215 (*ofield)->vec = v; 216 if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) 217 v->refcount += 1; 218 op->nfields += 1; 219 return 0; 220 } 221 222 /** 223 @brief Add a sub-operator to a composite CeedOperator 224 225 @param[out] compositeop Address of the composite CeedOperator 226 @param subop Address of the sub-operator CeedOperator 227 228 @return An error code: 0 - success, otherwise - failure 229 230 @ref Basic 231 */ 232 int CeedCompositeOperatorAddSub(CeedOperator compositeop, 233 CeedOperator subop) { 234 if (!compositeop->composite) 235 // LCOV_EXCL_START 236 return CeedError(compositeop->ceed, 1, "CeedOperator is not a composite " 237 "operator"); 238 // LCOV_EXCL_STOP 239 240 if (compositeop->numsub == CEED_COMPOSITE_MAX) 241 // LCOV_EXCL_START 242 return CeedError(compositeop->ceed, 1, "Cannot add additional suboperators"); 243 // LCOV_EXCL_STOP 244 245 compositeop->suboperators[compositeop->numsub] = subop; 246 subop->refcount++; 247 compositeop->numsub++; 248 return 0; 249 } 250 251 /** 252 @brief Assemble a linear CeedQFunction associated with a CeedOperator 253 254 This returns a CeedVector containing a matrix at each quadrature point 255 providing the action of the CeedQFunction associated with the CeedOperator. 256 The vector 'assembled' is of shape 257 [num_elements, num_input_fields, num_output_fields, num_quad_points] 258 and contains column-major matrices representing the action of the 259 CeedQFunction for a corresponding quadrature point on an element. Inputs and 260 outputs are in the order provided by the user when adding CeedOperator fields. 261 For example, a QFunction with inputs 'u' and 'gradu' and outputs 'gradv' and 262 'v', provided in that order, would result in an assembled QFunction that 263 consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting 264 on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v]. 265 266 @param op CeedOperator to assemble CeedQFunction 267 @param[out] assembled CeedVector to store assembled Ceed QFunction at 268 quadrature points 269 @param[out] rstr CeedElemRestriction for CeedVector containing assembled 270 CeedQFunction 271 @param request Address of CeedRequest for non-blocking completion, else 272 CEED_REQUEST_IMMEDIATE 273 274 @return An error code: 0 - success, otherwise - failure 275 276 @ref Advanced 277 **/ 278 int CeedOperatorAssembleLinearQFunction(CeedOperator op, CeedVector *assembled, 279 CeedElemRestriction *rstr, CeedRequest *request) { 280 int ierr; 281 Ceed ceed = op->ceed; 282 CeedQFunction qf = op->qf; 283 284 if (op->composite) { 285 // LCOV_EXCL_START 286 return CeedError(ceed, 1, "Cannot assemble QFunction for composite operator"); 287 // LCOV_EXCL_STOP 288 } else { 289 if (op->nfields == 0) 290 // LCOV_EXCL_START 291 return CeedError(ceed, 1, "No operator fields set"); 292 // LCOV_EXCL_STOP 293 if (op->nfields < qf->numinputfields + qf->numoutputfields) 294 // LCOV_EXCL_START 295 return CeedError( ceed, 1, "Not all operator fields set"); 296 // LCOV_EXCL_STOP 297 if (op->numelements == 0) 298 // LCOV_EXCL_START 299 return CeedError(ceed, 1, "At least one restriction required"); 300 // LCOV_EXCL_STOP 301 if (op->numqpoints == 0) 302 // LCOV_EXCL_START 303 return CeedError(ceed, 1, "At least one non-collocated basis required"); 304 // LCOV_EXCL_STOP 305 } 306 ierr = op->AssembleLinearQFunction(op, assembled, rstr, request); 307 CeedChk(ierr); 308 return 0; 309 } 310 311 /** 312 @brief Apply CeedOperator to a vector 313 314 This computes the action of the operator on the specified (active) input, 315 yielding its (active) output. All inputs and outputs must be specified using 316 CeedOperatorSetField(). 317 318 @param op CeedOperator to apply 319 @param[in] in CeedVector containing input state or NULL if there are no 320 active inputs 321 @param[out] out CeedVector to store result of applying operator (must be 322 distinct from @a in) or NULL if there are no active outputs 323 @param request Address of CeedRequest for non-blocking completion, else 324 CEED_REQUEST_IMMEDIATE 325 326 @return An error code: 0 - success, otherwise - failure 327 328 @ref Basic 329 **/ 330 int CeedOperatorApply(CeedOperator op, CeedVector in, 331 CeedVector out, CeedRequest *request) { 332 int ierr; 333 Ceed ceed = op->ceed; 334 CeedQFunction qf = op->qf; 335 336 if (op->composite) { 337 if (!op->numsub) 338 // LCOV_EXCL_START 339 return CeedError(ceed, 1, "No suboperators set"); 340 // LCOV_EXCL_STOP 341 } else { 342 if (op->nfields == 0) 343 // LCOV_EXCL_START 344 return CeedError(ceed, 1, "No operator fields set"); 345 // LCOV_EXCL_STOP 346 if (op->nfields < qf->numinputfields + qf->numoutputfields) 347 // LCOV_EXCL_START 348 return CeedError(ceed, 1, "Not all operator fields set"); 349 // LCOV_EXCL_STOP 350 if (op->numelements == 0) 351 // LCOV_EXCL_START 352 return CeedError(ceed, 1,"At least one restriction required"); 353 // LCOV_EXCL_STOP 354 if (op->numqpoints == 0) 355 // LCOV_EXCL_START 356 return CeedError(ceed, 1,"At least one non-collocated basis required"); 357 // LCOV_EXCL_STOP 358 } 359 ierr = op->Apply(op, in, out, request); CeedChk(ierr); 360 return 0; 361 } 362 363 /** 364 @brief Get the Ceed associated with a CeedOperator 365 366 @param op CeedOperator 367 @param[out] ceed Variable to store Ceed 368 369 @return An error code: 0 - success, otherwise - failure 370 371 @ref Advanced 372 **/ 373 374 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) { 375 *ceed = op->ceed; 376 return 0; 377 } 378 379 /** 380 @brief Get the number of elements associated with a CeedOperator 381 382 @param op CeedOperator 383 @param[out] numelem Variable to store number of elements 384 385 @return An error code: 0 - success, otherwise - failure 386 387 @ref Advanced 388 **/ 389 390 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) { 391 if (op->composite) 392 // LCOV_EXCL_START 393 return CeedError(op->ceed, 1, "Not defined for composite operator"); 394 // LCOV_EXCL_STOP 395 396 *numelem = op->numelements; 397 return 0; 398 } 399 400 /** 401 @brief Get the number of quadrature points associated with a CeedOperator 402 403 @param op CeedOperator 404 @param[out] numqpts Variable to store vector number of quadrature points 405 406 @return An error code: 0 - success, otherwise - failure 407 408 @ref Advanced 409 **/ 410 411 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) { 412 if (op->composite) 413 // LCOV_EXCL_START 414 return CeedError(op->ceed, 1, "Not defined for composite operator"); 415 // LCOV_EXCL_STOP 416 417 *numqpts = op->numqpoints; 418 return 0; 419 } 420 421 /** 422 @brief Get the number of arguments associated with a CeedOperator 423 424 @param op CeedOperator 425 @param[out] numargs Variable to store vector number of arguments 426 427 @return An error code: 0 - success, otherwise - failure 428 429 @ref Advanced 430 **/ 431 432 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) { 433 if (op->composite) 434 // LCOV_EXCL_START 435 return CeedError(op->ceed, 1, "Not defined for composite operators"); 436 // LCOV_EXCL_STOP 437 438 *numargs = op->nfields; 439 return 0; 440 } 441 442 /** 443 @brief Get the setup status of a CeedOperator 444 445 @param op CeedOperator 446 @param[out] setupdone Variable to store setup status 447 448 @return An error code: 0 - success, otherwise - failure 449 450 @ref Advanced 451 **/ 452 453 int CeedOperatorGetSetupStatus(CeedOperator op, bool *setupdone) { 454 *setupdone = op->setupdone; 455 return 0; 456 } 457 458 /** 459 @brief Get the QFunction associated with a CeedOperator 460 461 @param op CeedOperator 462 @param[out] qf Variable to store QFunction 463 464 @return An error code: 0 - success, otherwise - failure 465 466 @ref Advanced 467 **/ 468 469 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) { 470 if (op->composite) 471 // LCOV_EXCL_START 472 return CeedError(op->ceed, 1, "Not defined for composite operator"); 473 // LCOV_EXCL_STOP 474 475 *qf = op->qf; 476 return 0; 477 } 478 479 /** 480 @brief Get the number of suboperators associated with a CeedOperator 481 482 @param op CeedOperator 483 @param[out] numsub Variable to store number of suboperators 484 485 @return An error code: 0 - success, otherwise - failure 486 487 @ref Advanced 488 **/ 489 490 int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) { 491 if (!op->composite) 492 // LCOV_EXCL_START 493 return CeedError(op->ceed, 1, "Not a composite operator"); 494 // LCOV_EXCL_STOP 495 496 *numsub = op->numsub; 497 return 0; 498 } 499 500 /** 501 @brief Get the list of suboperators associated with a CeedOperator 502 503 @param op CeedOperator 504 @param[out] suboperators Variable to store list of suboperators 505 506 @return An error code: 0 - success, otherwise - failure 507 508 @ref Advanced 509 **/ 510 511 int CeedOperatorGetSubList(CeedOperator op, CeedOperator* *suboperators) { 512 if (!op->composite) 513 // LCOV_EXCL_START 514 return CeedError(op->ceed, 1, "Not a composite operator"); 515 // LCOV_EXCL_STOP 516 517 *suboperators = op->suboperators; 518 return 0; 519 } 520 521 /** 522 @brief Set the backend data of a CeedOperator 523 524 @param[out] op CeedOperator 525 @param data Data to set 526 527 @return An error code: 0 - success, otherwise - failure 528 529 @ref Advanced 530 **/ 531 532 int CeedOperatorSetData(CeedOperator op, void* *data) { 533 op->data = *data; 534 return 0; 535 } 536 537 /** 538 @brief Get the backend data of a CeedOperator 539 540 @param op CeedOperator 541 @param[out] data Variable to store data 542 543 @return An error code: 0 - success, otherwise - failure 544 545 @ref Advanced 546 **/ 547 548 int CeedOperatorGetData(CeedOperator op, void* *data) { 549 *data = op->data; 550 return 0; 551 } 552 553 /** 554 @brief Set the setup flag of a CeedOperator to True 555 556 @param op CeedOperator 557 558 @return An error code: 0 - success, otherwise - failure 559 560 @ref Advanced 561 **/ 562 563 int CeedOperatorSetSetupDone(CeedOperator op) { 564 op->setupdone = 1; 565 return 0; 566 } 567 568 /** 569 @brief Get the CeedOperatorFields of a CeedOperator 570 571 @param op CeedOperator 572 @param[out] inputfields Variable to store inputfields 573 @param[out] outputfields Variable to store outputfields 574 575 @return An error code: 0 - success, otherwise - failure 576 577 @ref Advanced 578 **/ 579 580 int CeedOperatorGetFields(CeedOperator op, 581 CeedOperatorField* *inputfields, 582 CeedOperatorField* *outputfields) { 583 if (op->composite) 584 // LCOV_EXCL_START 585 return CeedError(op->ceed, 1, "Not defined for composite operator"); 586 // LCOV_EXCL_STOP 587 588 if (inputfields) *inputfields = op->inputfields; 589 if (outputfields) *outputfields = op->outputfields; 590 return 0; 591 } 592 593 /** 594 @brief Get the L vector CeedTransposeMode of a CeedOperatorField 595 596 @param opfield CeedOperatorField 597 @param[out] lmode Variable to store CeedTransposeMode 598 599 @return An error code: 0 - success, otherwise - failure 600 601 @ref Advanced 602 **/ 603 604 int CeedOperatorFieldGetLMode(CeedOperatorField opfield, 605 CeedTransposeMode *lmode) { 606 *lmode = opfield->lmode; 607 return 0; 608 } 609 610 /** 611 @brief Get the CeedElemRestriction of a CeedOperatorField 612 613 @param opfield CeedOperatorField 614 @param[out] rstr Variable to store CeedElemRestriction 615 616 @return An error code: 0 - success, otherwise - failure 617 618 @ref Advanced 619 **/ 620 621 int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield, 622 CeedElemRestriction *rstr) { 623 *rstr = opfield->Erestrict; 624 return 0; 625 } 626 627 /** 628 @brief Get the CeedBasis of a CeedOperatorField 629 630 @param opfield CeedOperatorField 631 @param[out] basis Variable to store CeedBasis 632 633 @return An error code: 0 - success, otherwise - failure 634 635 @ref Advanced 636 **/ 637 638 int CeedOperatorFieldGetBasis(CeedOperatorField opfield, 639 CeedBasis *basis) { 640 *basis = opfield->basis; 641 return 0; 642 } 643 644 /** 645 @brief Get the CeedVector of a CeedOperatorField 646 647 @param opfield CeedOperatorField 648 @param[out] vec Variable to store CeedVector 649 650 @return An error code: 0 - success, otherwise - failure 651 652 @ref Advanced 653 **/ 654 655 int CeedOperatorFieldGetVector(CeedOperatorField opfield, 656 CeedVector *vec) { 657 *vec = opfield->vec; 658 return 0; 659 } 660 661 /** 662 @brief Destroy a CeedOperator 663 664 @param op CeedOperator to destroy 665 666 @return An error code: 0 - success, otherwise - failure 667 668 @ref Basic 669 **/ 670 int CeedOperatorDestroy(CeedOperator *op) { 671 int ierr; 672 673 if (!*op || --(*op)->refcount > 0) return 0; 674 if ((*op)->Destroy) { 675 ierr = (*op)->Destroy(*op); CeedChk(ierr); 676 } 677 ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr); 678 // Free fields 679 for (int i=0; i<(*op)->nfields; i++) 680 if ((*op)->inputfields[i]) { 681 ierr = CeedElemRestrictionDestroy(&(*op)->inputfields[i]->Erestrict); 682 CeedChk(ierr); 683 if ((*op)->inputfields[i]->basis != CEED_BASIS_COLLOCATED) { 684 ierr = CeedBasisDestroy(&(*op)->inputfields[i]->basis); CeedChk(ierr); 685 } 686 if ((*op)->inputfields[i]->vec != CEED_VECTOR_ACTIVE && 687 (*op)->inputfields[i]->vec != CEED_VECTOR_NONE ) { 688 ierr = CeedVectorDestroy(&(*op)->inputfields[i]->vec); CeedChk(ierr); 689 } 690 ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr); 691 } 692 for (int i=0; i<(*op)->nfields; i++) 693 if ((*op)->outputfields[i]) { 694 ierr = CeedElemRestrictionDestroy(&(*op)->outputfields[i]->Erestrict); 695 CeedChk(ierr); 696 if ((*op)->outputfields[i]->basis != CEED_BASIS_COLLOCATED) { 697 ierr = CeedBasisDestroy(&(*op)->outputfields[i]->basis); CeedChk(ierr); 698 } 699 if ((*op)->outputfields[i]->vec != CEED_VECTOR_ACTIVE && 700 (*op)->outputfields[i]->vec != CEED_VECTOR_NONE ) { 701 ierr = CeedVectorDestroy(&(*op)->outputfields[i]->vec); CeedChk(ierr); 702 } 703 ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr); 704 } 705 // Destroy suboperators 706 for (int i=0; i<(*op)->numsub; i++) 707 if ((*op)->suboperators[i]) { 708 ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr); 709 } 710 ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr); 711 ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr); 712 ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr); 713 714 ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr); 715 ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr); 716 ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr); 717 ierr = CeedFree(op); CeedChk(ierr); 718 return 0; 719 } 720 721 /// @} 722