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/ceed.h> 18 #include <ceed/backend.h> 19 #include <ceed-impl.h> 20 #include <stdbool.h> 21 #include <stdio.h> 22 #include <string.h> 23 24 /// @file 25 /// Implementation of CeedOperator interfaces 26 27 /// ---------------------------------------------------------------------------- 28 /// CeedOperator Library Internal Functions 29 /// ---------------------------------------------------------------------------- 30 /// @addtogroup CeedOperatorDeveloper 31 /// @{ 32 33 /** 34 @brief Check if a CeedOperator Field matches the QFunction Field 35 36 @param[in] ceed Ceed object for error handling 37 @param[in] qf_field QFunction Field matching Operator Field 38 @param[in] r Operator Field ElemRestriction 39 @param[in] b Operator Field Basis 40 41 @return An error code: 0 - success, otherwise - failure 42 43 @ref Developer 44 **/ 45 static int CeedOperatorCheckField(Ceed ceed, CeedQFunctionField qf_field, 46 CeedElemRestriction r, CeedBasis b) { 47 int ierr; 48 CeedEvalMode eval_mode = qf_field->eval_mode; 49 CeedInt dim = 1, num_comp = 1, restr_num_comp = 1, size = qf_field->size; 50 // Restriction 51 if (r != CEED_ELEMRESTRICTION_NONE) { 52 if (eval_mode == CEED_EVAL_WEIGHT) { 53 // LCOV_EXCL_START 54 return CeedError(ceed, CEED_ERROR_INCOMPATIBLE, 55 "CEED_ELEMRESTRICTION_NONE should be used " 56 "for a field with eval mode CEED_EVAL_WEIGHT"); 57 // LCOV_EXCL_STOP 58 } 59 ierr = CeedElemRestrictionGetNumComponents(r, &restr_num_comp); 60 CeedChk(ierr); 61 } 62 if ((r == CEED_ELEMRESTRICTION_NONE) != (eval_mode == CEED_EVAL_WEIGHT)) { 63 // LCOV_EXCL_START 64 return CeedError(ceed, CEED_ERROR_INCOMPATIBLE, 65 "CEED_ELEMRESTRICTION_NONE and CEED_EVAL_WEIGHT " 66 "must be used together."); 67 // LCOV_EXCL_STOP 68 } 69 // Basis 70 if (b != CEED_BASIS_COLLOCATED) { 71 if (eval_mode == CEED_EVAL_NONE) 72 // LCOV_EXCL_START 73 return CeedError(ceed, CEED_ERROR_INCOMPATIBLE, 74 "Field '%s' configured with CEED_EVAL_NONE must " 75 "be used with CEED_BASIS_COLLOCATED", 76 // LCOV_EXCL_STOP 77 qf_field->field_name); 78 ierr = CeedBasisGetDimension(b, &dim); CeedChk(ierr); 79 ierr = CeedBasisGetNumComponents(b, &num_comp); CeedChk(ierr); 80 if (r != CEED_ELEMRESTRICTION_NONE && restr_num_comp != num_comp) { 81 // LCOV_EXCL_START 82 return CeedError(ceed, CEED_ERROR_DIMENSION, 83 "Field '%s' of size %d and EvalMode %s: ElemRestriction " 84 "has %d components, but Basis has %d components", 85 qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], 86 restr_num_comp, 87 num_comp); 88 // LCOV_EXCL_STOP 89 } 90 } 91 // Field size 92 switch(eval_mode) { 93 case CEED_EVAL_NONE: 94 if (size != restr_num_comp) 95 // LCOV_EXCL_START 96 return CeedError(ceed, CEED_ERROR_DIMENSION, 97 "Field '%s' of size %d and EvalMode %s: ElemRestriction has %d components", 98 qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], 99 restr_num_comp); 100 // LCOV_EXCL_STOP 101 break; 102 case CEED_EVAL_INTERP: 103 if (size != num_comp) 104 // LCOV_EXCL_START 105 return CeedError(ceed, CEED_ERROR_DIMENSION, 106 "Field '%s' of size %d and EvalMode %s: ElemRestriction/Basis has %d components", 107 qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], 108 num_comp); 109 // LCOV_EXCL_STOP 110 break; 111 case CEED_EVAL_GRAD: 112 if (size != num_comp * dim) 113 // LCOV_EXCL_START 114 return CeedError(ceed, CEED_ERROR_DIMENSION, 115 "Field '%s' of size %d and EvalMode %s in %d dimensions: " 116 "ElemRestriction/Basis has %d components", 117 qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], dim, 118 num_comp); 119 // LCOV_EXCL_STOP 120 break; 121 case CEED_EVAL_WEIGHT: 122 // No additional checks required 123 break; 124 case CEED_EVAL_DIV: 125 // Not implemented 126 break; 127 case CEED_EVAL_CURL: 128 // Not implemented 129 break; 130 } 131 return CEED_ERROR_SUCCESS; 132 } 133 134 /** 135 @brief View a field of a CeedOperator 136 137 @param[in] field Operator field to view 138 @param[in] qf_field QFunction field (carries field name) 139 @param[in] field_number Number of field being viewed 140 @param[in] sub true indicates sub-operator, which increases indentation; false for top-level operator 141 @param[in] input true for an input field; false for output field 142 @param[in] stream Stream to view to, e.g., stdout 143 144 @return An error code: 0 - success, otherwise - failure 145 146 @ref Utility 147 **/ 148 static int CeedOperatorFieldView(CeedOperatorField field, 149 CeedQFunctionField qf_field, 150 CeedInt field_number, bool sub, bool input, 151 FILE *stream) { 152 const char *pre = sub ? " " : ""; 153 const char *in_out = input ? "Input" : "Output"; 154 155 fprintf(stream, "%s %s Field [%d]:\n" 156 "%s Name: \"%s\"\n", 157 pre, in_out, field_number, pre, qf_field->field_name); 158 159 if (field->basis == CEED_BASIS_COLLOCATED) 160 fprintf(stream, "%s Collocated basis\n", pre); 161 162 if (field->vec == CEED_VECTOR_ACTIVE) 163 fprintf(stream, "%s Active vector\n", pre); 164 else if (field->vec == CEED_VECTOR_NONE) 165 fprintf(stream, "%s No vector\n", pre); 166 return CEED_ERROR_SUCCESS; 167 } 168 169 /** 170 @brief View a single CeedOperator 171 172 @param[in] op CeedOperator to view 173 @param[in] sub Boolean flag for sub-operator 174 @param[in] stream Stream to write; typically stdout/stderr or a file 175 176 @return Error code: 0 - success, otherwise - failure 177 178 @ref Utility 179 **/ 180 int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) { 181 int ierr; 182 const char *pre = sub ? " " : ""; 183 184 CeedInt total_fields = 0; 185 ierr = CeedOperatorGetNumArgs(op, &total_fields); CeedChk(ierr); 186 187 fprintf(stream, "%s %d Field%s\n", pre, total_fields, 188 total_fields>1 ? "s" : ""); 189 190 fprintf(stream, "%s %d Input Field%s:\n", pre, op->qf->num_input_fields, 191 op->qf->num_input_fields>1 ? "s" : ""); 192 for (CeedInt i=0; i<op->qf->num_input_fields; i++) { 193 ierr = CeedOperatorFieldView(op->input_fields[i], op->qf->input_fields[i], 194 i, sub, 1, stream); CeedChk(ierr); 195 } 196 197 fprintf(stream, "%s %d Output Field%s:\n", pre, op->qf->num_output_fields, 198 op->qf->num_output_fields>1 ? "s" : ""); 199 for (CeedInt i=0; i<op->qf->num_output_fields; i++) { 200 ierr = CeedOperatorFieldView(op->output_fields[i], op->qf->output_fields[i], 201 i, sub, 0, stream); CeedChk(ierr); 202 } 203 return CEED_ERROR_SUCCESS; 204 } 205 206 /** 207 @brief Find the active vector basis for a CeedOperator 208 209 @param[in] op CeedOperator to find active basis for 210 @param[out] active_basis Basis for active input vector 211 212 @return An error code: 0 - success, otherwise - failure 213 214 @ ref Developer 215 **/ 216 int CeedOperatorGetActiveBasis(CeedOperator op, CeedBasis *active_basis) { 217 *active_basis = NULL; 218 for (int i = 0; i < op->qf->num_input_fields; i++) 219 if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) { 220 *active_basis = op->input_fields[i]->basis; 221 break; 222 } 223 224 if (!*active_basis) { 225 // LCOV_EXCL_START 226 int ierr; 227 Ceed ceed; 228 ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); 229 return CeedError(ceed, CEED_ERROR_MINOR, 230 "No active CeedBasis found"); 231 // LCOV_EXCL_STOP 232 } 233 return CEED_ERROR_SUCCESS; 234 } 235 236 /** 237 @brief Find the active vector ElemRestriction for a CeedOperator 238 239 @param[in] op CeedOperator to find active basis for 240 @param[out] active_rstr ElemRestriction for active input vector 241 242 @return An error code: 0 - success, otherwise - failure 243 244 @ref Utility 245 **/ 246 int CeedOperatorGetActiveElemRestriction(CeedOperator op, 247 CeedElemRestriction *active_rstr) { 248 *active_rstr = NULL; 249 for (int i = 0; i < op->qf->num_input_fields; i++) 250 if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) { 251 *active_rstr = op->input_fields[i]->elem_restr; 252 break; 253 } 254 255 if (!*active_rstr) { 256 // LCOV_EXCL_START 257 int ierr; 258 Ceed ceed; 259 ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); 260 return CeedError(ceed, CEED_ERROR_INCOMPLETE, 261 "No active CeedElemRestriction found"); 262 // LCOV_EXCL_STOP 263 } 264 return CEED_ERROR_SUCCESS; 265 } 266 267 /** 268 @brief Set QFunctionContext field value of the specified type. 269 For composite operators, the value is set in all 270 sub-operator QFunctionContexts that have a matching `field_name`. 271 A non-zero error code is returned for single operators 272 that do not have a matching field of the same type or composite 273 operators that do not have any field of a matching type. 274 275 @param op CeedOperator 276 @param field_name Name of field to set 277 @param field_type Type of field to set 278 @param value Value to set 279 280 @return An error code: 0 - success, otherwise - failure 281 282 @ref User 283 **/ 284 static int CeedOperatorContextSetGeneric(CeedOperator op, 285 const char *field_name, CeedContextFieldType field_type, void *value) { 286 int ierr; 287 bool is_set = false, is_composite = false; 288 289 ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 290 291 if (is_composite) { 292 CeedInt num_sub; 293 CeedOperator *sub_operators; 294 295 ierr = CeedOperatorGetNumSub(op, &num_sub); CeedChk(ierr); 296 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 297 298 for (CeedInt i = 0; i < num_sub; i++) { 299 // Try every sub-operator, ok if some sub-operators do not have field 300 if (sub_operators[i]->qf->ctx) { 301 bool is_set_i = false; 302 ierr = CeedQFunctionContextSetGeneric(sub_operators[i]->qf->ctx, field_name, 303 field_type, &is_set_i, value); 304 CeedChk(ierr); 305 is_set = is_set || is_set_i; 306 } 307 } 308 } else { 309 if (!op->qf->ctx) 310 // LCOV_EXCL_START 311 return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, 312 "QFunction does not have context data"); 313 // LCOV_EXCL_STOP 314 315 ierr = CeedQFunctionContextSetGeneric(op->qf->ctx, field_name, 316 field_type, &is_set, value); CeedChk(ierr); 317 } 318 319 if (!is_set) 320 // LCOV_EXCL_START 321 return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, 322 "QFunctionContext field with name \"%s\" not registered", 323 field_name); 324 // LCOV_EXCL_STOP 325 326 return CEED_ERROR_SUCCESS; 327 } 328 329 /// @} 330 331 /// ---------------------------------------------------------------------------- 332 /// CeedOperator Backend API 333 /// ---------------------------------------------------------------------------- 334 /// @addtogroup CeedOperatorBackend 335 /// @{ 336 337 /** 338 @brief Get the number of arguments associated with a CeedOperator 339 340 @param op CeedOperator 341 @param[out] num_args Variable to store vector number of arguments 342 343 @return An error code: 0 - success, otherwise - failure 344 345 @ref Backend 346 **/ 347 348 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *num_args) { 349 if (op->is_composite) 350 // LCOV_EXCL_START 351 return CeedError(op->ceed, CEED_ERROR_MINOR, 352 "Not defined for composite operators"); 353 // LCOV_EXCL_STOP 354 355 *num_args = op->num_fields; 356 return CEED_ERROR_SUCCESS; 357 } 358 359 /** 360 @brief Get the setup status of a CeedOperator 361 362 @param op CeedOperator 363 @param[out] is_setup_done Variable to store setup status 364 365 @return An error code: 0 - success, otherwise - failure 366 367 @ref Backend 368 **/ 369 370 int CeedOperatorIsSetupDone(CeedOperator op, bool *is_setup_done) { 371 *is_setup_done = op->is_backend_setup; 372 return CEED_ERROR_SUCCESS; 373 } 374 375 /** 376 @brief Get the QFunction associated with a CeedOperator 377 378 @param op CeedOperator 379 @param[out] qf Variable to store QFunction 380 381 @return An error code: 0 - success, otherwise - failure 382 383 @ref Backend 384 **/ 385 386 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) { 387 if (op->is_composite) 388 // LCOV_EXCL_START 389 return CeedError(op->ceed, CEED_ERROR_MINOR, 390 "Not defined for composite operator"); 391 // LCOV_EXCL_STOP 392 393 *qf = op->qf; 394 return CEED_ERROR_SUCCESS; 395 } 396 397 /** 398 @brief Get a boolean value indicating if the CeedOperator is composite 399 400 @param op CeedOperator 401 @param[out] is_composite Variable to store composite status 402 403 @return An error code: 0 - success, otherwise - failure 404 405 @ref Backend 406 **/ 407 408 int CeedOperatorIsComposite(CeedOperator op, bool *is_composite) { 409 *is_composite = op->is_composite; 410 return CEED_ERROR_SUCCESS; 411 } 412 413 /** 414 @brief Get the number of sub_operators associated with a CeedOperator 415 416 @param op CeedOperator 417 @param[out] num_suboperators Variable to store number of sub_operators 418 419 @return An error code: 0 - success, otherwise - failure 420 421 @ref Backend 422 **/ 423 424 int CeedOperatorGetNumSub(CeedOperator op, CeedInt *num_suboperators) { 425 if (!op->is_composite) 426 // LCOV_EXCL_START 427 return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator"); 428 // LCOV_EXCL_STOP 429 430 *num_suboperators = op->num_suboperators; 431 return CEED_ERROR_SUCCESS; 432 } 433 434 /** 435 @brief Get the list of sub_operators associated with a CeedOperator 436 437 @param op CeedOperator 438 @param[out] sub_operators Variable to store list of sub_operators 439 440 @return An error code: 0 - success, otherwise - failure 441 442 @ref Backend 443 **/ 444 445 int CeedOperatorGetSubList(CeedOperator op, CeedOperator **sub_operators) { 446 if (!op->is_composite) 447 // LCOV_EXCL_START 448 return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator"); 449 // LCOV_EXCL_STOP 450 451 *sub_operators = op->sub_operators; 452 return CEED_ERROR_SUCCESS; 453 } 454 455 /** 456 @brief Get the backend data of a CeedOperator 457 458 @param op CeedOperator 459 @param[out] data Variable to store data 460 461 @return An error code: 0 - success, otherwise - failure 462 463 @ref Backend 464 **/ 465 466 int CeedOperatorGetData(CeedOperator op, void *data) { 467 *(void **)data = op->data; 468 return CEED_ERROR_SUCCESS; 469 } 470 471 /** 472 @brief Set the backend data of a CeedOperator 473 474 @param[out] op CeedOperator 475 @param data Data to set 476 477 @return An error code: 0 - success, otherwise - failure 478 479 @ref Backend 480 **/ 481 482 int CeedOperatorSetData(CeedOperator op, void *data) { 483 op->data = data; 484 return CEED_ERROR_SUCCESS; 485 } 486 487 /** 488 @brief Increment the reference counter for a CeedOperator 489 490 @param op CeedOperator to increment the reference counter 491 492 @return An error code: 0 - success, otherwise - failure 493 494 @ref Backend 495 **/ 496 int CeedOperatorReference(CeedOperator op) { 497 op->ref_count++; 498 return CEED_ERROR_SUCCESS; 499 } 500 501 /** 502 @brief Set the setup flag of a CeedOperator to True 503 504 @param op CeedOperator 505 506 @return An error code: 0 - success, otherwise - failure 507 508 @ref Backend 509 **/ 510 511 int CeedOperatorSetSetupDone(CeedOperator op) { 512 op->is_backend_setup = true; 513 return CEED_ERROR_SUCCESS; 514 } 515 516 /// @} 517 518 /// ---------------------------------------------------------------------------- 519 /// CeedOperator Public API 520 /// ---------------------------------------------------------------------------- 521 /// @addtogroup CeedOperatorUser 522 /// @{ 523 524 /** 525 @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and 526 CeedElemRestriction can be associated with CeedQFunction fields with 527 \ref CeedOperatorSetField. 528 529 @param ceed A Ceed object where the CeedOperator will be created 530 @param qf QFunction defining the action of the operator at quadrature points 531 @param dqf QFunction defining the action of the Jacobian of @a qf (or 532 @ref CEED_QFUNCTION_NONE) 533 @param dqfT QFunction defining the action of the transpose of the Jacobian 534 of @a qf (or @ref CEED_QFUNCTION_NONE) 535 @param[out] op Address of the variable where the newly created 536 CeedOperator will be stored 537 538 @return An error code: 0 - success, otherwise - failure 539 540 @ref User 541 */ 542 int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, 543 CeedQFunction dqfT, CeedOperator *op) { 544 int ierr; 545 546 if (!ceed->OperatorCreate) { 547 Ceed delegate; 548 ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr); 549 550 if (!delegate) 551 // LCOV_EXCL_START 552 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 553 "Backend does not support OperatorCreate"); 554 // LCOV_EXCL_STOP 555 556 ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr); 557 return CEED_ERROR_SUCCESS; 558 } 559 560 if (!qf || qf == CEED_QFUNCTION_NONE) 561 // LCOV_EXCL_START 562 return CeedError(ceed, CEED_ERROR_MINOR, 563 "Operator must have a valid QFunction."); 564 // LCOV_EXCL_STOP 565 ierr = CeedCalloc(1, op); CeedChk(ierr); 566 (*op)->ceed = ceed; 567 ierr = CeedReference(ceed); CeedChk(ierr); 568 (*op)->ref_count = 1; 569 (*op)->qf = qf; 570 ierr = CeedQFunctionReference(qf); CeedChk(ierr); 571 if (dqf && dqf != CEED_QFUNCTION_NONE) { 572 (*op)->dqf = dqf; 573 ierr = CeedQFunctionReference(dqf); CeedChk(ierr); 574 } 575 if (dqfT && dqfT != CEED_QFUNCTION_NONE) { 576 (*op)->dqfT = dqfT; 577 ierr = CeedQFunctionReference(dqfT); CeedChk(ierr); 578 } 579 ierr = CeedCalloc(CEED_FIELD_MAX, &(*op)->input_fields); CeedChk(ierr); 580 ierr = CeedCalloc(CEED_FIELD_MAX, &(*op)->output_fields); CeedChk(ierr); 581 ierr = ceed->OperatorCreate(*op); CeedChk(ierr); 582 return CEED_ERROR_SUCCESS; 583 } 584 585 /** 586 @brief Create an operator that composes the action of several operators 587 588 @param ceed A Ceed object where the CeedOperator will be created 589 @param[out] op Address of the variable where the newly created 590 Composite CeedOperator will be stored 591 592 @return An error code: 0 - success, otherwise - failure 593 594 @ref User 595 */ 596 int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) { 597 int ierr; 598 599 if (!ceed->CompositeOperatorCreate) { 600 Ceed delegate; 601 ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr); 602 603 if (delegate) { 604 ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr); 605 return CEED_ERROR_SUCCESS; 606 } 607 } 608 609 ierr = CeedCalloc(1, op); CeedChk(ierr); 610 (*op)->ceed = ceed; 611 ierr = CeedReference(ceed); CeedChk(ierr); 612 (*op)->is_composite = true; 613 ierr = CeedCalloc(CEED_COMPOSITE_MAX, &(*op)->sub_operators); CeedChk(ierr); 614 615 if (ceed->CompositeOperatorCreate) { 616 ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr); 617 } 618 return CEED_ERROR_SUCCESS; 619 } 620 621 /** 622 @brief Copy the pointer to a CeedOperator. Both pointers should 623 be destroyed with `CeedOperatorDestroy()`; 624 Note: If `*op_copy` is non-NULL, then it is assumed that 625 `*op_copy` is a pointer to a CeedOperator. This 626 CeedOperator will be destroyed if `*op_copy` is the only 627 reference to this CeedOperator. 628 629 @param op CeedOperator to copy reference to 630 @param[out] op_copy Variable to store copied reference 631 632 @return An error code: 0 - success, otherwise - failure 633 634 @ref User 635 **/ 636 int CeedOperatorReferenceCopy(CeedOperator op, CeedOperator *op_copy) { 637 int ierr; 638 639 ierr = CeedOperatorReference(op); CeedChk(ierr); 640 ierr = CeedOperatorDestroy(op_copy); CeedChk(ierr); 641 *op_copy = op; 642 return CEED_ERROR_SUCCESS; 643 } 644 645 /** 646 @brief Provide a field to a CeedOperator for use by its CeedQFunction 647 648 This function is used to specify both active and passive fields to a 649 CeedOperator. For passive fields, a vector @arg v must be provided. Passive 650 fields can inputs or outputs (updated in-place when operator is applied). 651 652 Active fields must be specified using this function, but their data (in a 653 CeedVector) is passed in CeedOperatorApply(). There can be at most one active 654 input and at most one active output. 655 656 @param op CeedOperator on which to provide the field 657 @param field_name Name of the field (to be matched with the name used by 658 CeedQFunction) 659 @param r CeedElemRestriction 660 @param b CeedBasis in which the field resides or @ref CEED_BASIS_COLLOCATED 661 if collocated with quadrature points 662 @param v CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE 663 if field is active or @ref CEED_VECTOR_NONE if using 664 @ref CEED_EVAL_WEIGHT in the QFunction 665 666 @return An error code: 0 - success, otherwise - failure 667 668 @ref User 669 **/ 670 int CeedOperatorSetField(CeedOperator op, const char *field_name, 671 CeedElemRestriction r, CeedBasis b, CeedVector v) { 672 int ierr; 673 if (op->is_composite) 674 // LCOV_EXCL_START 675 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 676 "Cannot add field to composite operator."); 677 // LCOV_EXCL_STOP 678 if (op->is_immutable) 679 // LCOV_EXCL_START 680 return CeedError(op->ceed, CEED_ERROR_MAJOR, 681 "Operator cannot be changed after set as immutable"); 682 // LCOV_EXCL_STOP 683 if (!r) 684 // LCOV_EXCL_START 685 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 686 "ElemRestriction r for field \"%s\" must be non-NULL.", 687 field_name); 688 // LCOV_EXCL_STOP 689 if (!b) 690 // LCOV_EXCL_START 691 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 692 "Basis b for field \"%s\" must be non-NULL.", 693 field_name); 694 // LCOV_EXCL_STOP 695 if (!v) 696 // LCOV_EXCL_START 697 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 698 "Vector v for field \"%s\" must be non-NULL.", 699 field_name); 700 // LCOV_EXCL_STOP 701 702 CeedInt num_elem; 703 ierr = CeedElemRestrictionGetNumElements(r, &num_elem); CeedChk(ierr); 704 if (r != CEED_ELEMRESTRICTION_NONE && op->has_restriction && 705 op->num_elem != num_elem) 706 // LCOV_EXCL_START 707 return CeedError(op->ceed, CEED_ERROR_DIMENSION, 708 "ElemRestriction with %d elements incompatible with prior " 709 "%d elements", num_elem, op->num_elem); 710 // LCOV_EXCL_STOP 711 712 CeedInt num_qpts = 0; 713 if (b != CEED_BASIS_COLLOCATED) { 714 ierr = CeedBasisGetNumQuadraturePoints(b, &num_qpts); CeedChk(ierr); 715 if (op->num_qpts && op->num_qpts != num_qpts) 716 // LCOV_EXCL_START 717 return CeedError(op->ceed, CEED_ERROR_DIMENSION, 718 "Basis with %d quadrature points " 719 "incompatible with prior %d points", num_qpts, 720 op->num_qpts); 721 // LCOV_EXCL_STOP 722 } 723 CeedQFunctionField qf_field; 724 CeedOperatorField *op_field; 725 for (CeedInt i=0; i<op->qf->num_input_fields; i++) { 726 if (!strcmp(field_name, (*op->qf->input_fields[i]).field_name)) { 727 qf_field = op->qf->input_fields[i]; 728 op_field = &op->input_fields[i]; 729 goto found; 730 } 731 } 732 for (CeedInt i=0; i<op->qf->num_output_fields; i++) { 733 if (!strcmp(field_name, (*op->qf->output_fields[i]).field_name)) { 734 qf_field = op->qf->output_fields[i]; 735 op_field = &op->output_fields[i]; 736 goto found; 737 } 738 } 739 // LCOV_EXCL_START 740 return CeedError(op->ceed, CEED_ERROR_INCOMPLETE, 741 "QFunction has no knowledge of field '%s'", 742 field_name); 743 // LCOV_EXCL_STOP 744 found: 745 ierr = CeedOperatorCheckField(op->ceed, qf_field, r, b); CeedChk(ierr); 746 ierr = CeedCalloc(1, op_field); CeedChk(ierr); 747 748 (*op_field)->vec = v; 749 if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) { 750 ierr = CeedVectorReference(v); CeedChk(ierr); 751 } 752 753 (*op_field)->elem_restr = r; 754 ierr = CeedElemRestrictionReference(r); CeedChk(ierr); 755 if (r != CEED_ELEMRESTRICTION_NONE) { 756 op->num_elem = num_elem; 757 op->has_restriction = true; // Restriction set, but num_elem may be 0 758 } 759 760 (*op_field)->basis = b; 761 if (b != CEED_BASIS_COLLOCATED) { 762 if (!op->num_qpts) { 763 ierr = CeedOperatorSetNumQuadraturePoints(op, num_qpts); CeedChk(ierr); 764 } 765 ierr = CeedBasisReference(b); CeedChk(ierr); 766 } 767 768 op->num_fields += 1; 769 ierr = CeedStringAllocCopy(field_name, (char **)&(*op_field)->field_name); 770 CeedChk(ierr); 771 return CEED_ERROR_SUCCESS; 772 } 773 774 /** 775 @brief Get the CeedOperatorFields of a CeedOperator 776 777 Note: Calling this function asserts that setup is complete 778 and sets the CeedOperator as immutable. 779 780 @param op CeedOperator 781 @param[out] num_input_fields Variable to store number of input fields 782 @param[out] input_fields Variable to store input_fields 783 @param[out] num_output_fields Variable to store number of output fields 784 @param[out] output_fields Variable to store output_fields 785 786 @return An error code: 0 - success, otherwise - failure 787 788 @ref Advanced 789 **/ 790 int CeedOperatorGetFields(CeedOperator op, CeedInt *num_input_fields, 791 CeedOperatorField **input_fields, 792 CeedInt *num_output_fields, 793 CeedOperatorField **output_fields) { 794 int ierr; 795 796 if (op->is_composite) 797 // LCOV_EXCL_START 798 return CeedError(op->ceed, CEED_ERROR_MINOR, 799 "Not defined for composite operator"); 800 // LCOV_EXCL_STOP 801 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 802 803 if (num_input_fields) *num_input_fields = op->qf->num_input_fields; 804 if (input_fields) *input_fields = op->input_fields; 805 if (num_output_fields) *num_output_fields = op->qf->num_output_fields; 806 if (output_fields) *output_fields = op->output_fields; 807 return CEED_ERROR_SUCCESS; 808 } 809 810 /** 811 @brief Get the name of a CeedOperatorField 812 813 @param op_field CeedOperatorField 814 @param[out] field_name Variable to store the field name 815 816 @return An error code: 0 - success, otherwise - failure 817 818 @ref Advanced 819 **/ 820 int CeedOperatorFieldGetName(CeedOperatorField op_field, char **field_name) { 821 *field_name = (char *)op_field->field_name; 822 return CEED_ERROR_SUCCESS; 823 } 824 825 /** 826 @brief Get the CeedElemRestriction of a CeedOperatorField 827 828 @param op_field CeedOperatorField 829 @param[out] rstr Variable to store CeedElemRestriction 830 831 @return An error code: 0 - success, otherwise - failure 832 833 @ref Advanced 834 **/ 835 int CeedOperatorFieldGetElemRestriction(CeedOperatorField op_field, 836 CeedElemRestriction *rstr) { 837 *rstr = op_field->elem_restr; 838 return CEED_ERROR_SUCCESS; 839 } 840 841 /** 842 @brief Get the CeedBasis of a CeedOperatorField 843 844 @param op_field CeedOperatorField 845 @param[out] basis Variable to store CeedBasis 846 847 @return An error code: 0 - success, otherwise - failure 848 849 @ref Advanced 850 **/ 851 int CeedOperatorFieldGetBasis(CeedOperatorField op_field, CeedBasis *basis) { 852 *basis = op_field->basis; 853 return CEED_ERROR_SUCCESS; 854 } 855 856 /** 857 @brief Get the CeedVector of a CeedOperatorField 858 859 @param op_field CeedOperatorField 860 @param[out] vec Variable to store CeedVector 861 862 @return An error code: 0 - success, otherwise - failure 863 864 @ref Advanced 865 **/ 866 int CeedOperatorFieldGetVector(CeedOperatorField op_field, CeedVector *vec) { 867 *vec = op_field->vec; 868 return CEED_ERROR_SUCCESS; 869 } 870 871 /** 872 @brief Add a sub-operator to a composite CeedOperator 873 874 @param[out] composite_op Composite CeedOperator 875 @param sub_op Sub-operator CeedOperator 876 877 @return An error code: 0 - success, otherwise - failure 878 879 @ref User 880 */ 881 int CeedCompositeOperatorAddSub(CeedOperator composite_op, 882 CeedOperator sub_op) { 883 int ierr; 884 885 if (!composite_op->is_composite) 886 // LCOV_EXCL_START 887 return CeedError(composite_op->ceed, CEED_ERROR_MINOR, 888 "CeedOperator is not a composite operator"); 889 // LCOV_EXCL_STOP 890 891 if (composite_op->num_suboperators == CEED_COMPOSITE_MAX) 892 // LCOV_EXCL_START 893 return CeedError(composite_op->ceed, CEED_ERROR_UNSUPPORTED, 894 "Cannot add additional sub_operators"); 895 // LCOV_EXCL_STOP 896 if (composite_op->is_immutable) 897 // LCOV_EXCL_START 898 return CeedError(composite_op->ceed, CEED_ERROR_MAJOR, 899 "Operator cannot be changed after set as immutable"); 900 // LCOV_EXCL_STOP 901 902 composite_op->sub_operators[composite_op->num_suboperators] = sub_op; 903 ierr = CeedOperatorReference(sub_op); CeedChk(ierr); 904 composite_op->num_suboperators++; 905 return CEED_ERROR_SUCCESS; 906 } 907 908 /** 909 @brief Check if a CeedOperator is ready to be used. 910 911 @param[in] op CeedOperator to check 912 913 @return An error code: 0 - success, otherwise - failure 914 915 @ref User 916 **/ 917 int CeedOperatorCheckReady(CeedOperator op) { 918 int ierr; 919 Ceed ceed; 920 ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); 921 922 if (op->is_interface_setup) 923 return CEED_ERROR_SUCCESS; 924 925 CeedQFunction qf = op->qf; 926 if (op->is_composite) { 927 if (!op->num_suboperators) 928 // LCOV_EXCL_START 929 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No sub_operators set"); 930 // LCOV_EXCL_STOP 931 for (CeedInt i = 0; i < op->num_suboperators; i++) { 932 ierr = CeedOperatorCheckReady(op->sub_operators[i]); CeedChk(ierr); 933 } 934 } else { 935 if (op->num_fields == 0) 936 // LCOV_EXCL_START 937 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No operator fields set"); 938 // LCOV_EXCL_STOP 939 if (op->num_fields < qf->num_input_fields + qf->num_output_fields) 940 // LCOV_EXCL_START 941 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set"); 942 // LCOV_EXCL_STOP 943 if (!op->has_restriction) 944 // LCOV_EXCL_START 945 return CeedError(ceed, CEED_ERROR_INCOMPLETE, 946 "At least one restriction required"); 947 // LCOV_EXCL_STOP 948 if (op->num_qpts == 0) 949 // LCOV_EXCL_START 950 return CeedError(ceed, CEED_ERROR_INCOMPLETE, 951 "At least one non-collocated basis is required " 952 "or the number of quadrature points must be set"); 953 // LCOV_EXCL_STOP 954 } 955 956 // Flag as immutable and ready 957 op->is_interface_setup = true; 958 if (op->qf && op->qf != CEED_QFUNCTION_NONE) 959 // LCOV_EXCL_START 960 op->qf->is_immutable = true; 961 // LCOV_EXCL_STOP 962 if (op->dqf && op->dqf != CEED_QFUNCTION_NONE) 963 // LCOV_EXCL_START 964 op->dqf->is_immutable = true; 965 // LCOV_EXCL_STOP 966 if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE) 967 // LCOV_EXCL_START 968 op->dqfT->is_immutable = true; 969 // LCOV_EXCL_STOP 970 return CEED_ERROR_SUCCESS; 971 } 972 973 /** 974 @brief Set the number of quadrature points associated with a CeedOperator. 975 This should be used when creating a CeedOperator where every 976 field has a collocated basis. This function cannot be used for 977 composite CeedOperators. 978 979 @param op CeedOperator 980 @param num_qpts Number of quadrature points to set 981 982 @return An error code: 0 - success, otherwise - failure 983 984 @ref Advanced 985 **/ 986 int CeedOperatorSetNumQuadraturePoints(CeedOperator op, CeedInt num_qpts) { 987 if (op->is_composite) 988 // LCOV_EXCL_START 989 return CeedError(op->ceed, CEED_ERROR_MINOR, 990 "Not defined for composite operator"); 991 // LCOV_EXCL_STOP 992 if (op->num_qpts) 993 // LCOV_EXCL_START 994 return CeedError(op->ceed, CEED_ERROR_MINOR, 995 "Number of quadrature points already defined"); 996 // LCOV_EXCL_STOP 997 if (op->is_immutable) 998 // LCOV_EXCL_START 999 return CeedError(op->ceed, CEED_ERROR_MAJOR, 1000 "Operator cannot be changed after set as immutable"); 1001 // LCOV_EXCL_STOP 1002 1003 op->num_qpts = num_qpts; 1004 return CEED_ERROR_SUCCESS; 1005 } 1006 1007 /** 1008 @brief View a CeedOperator 1009 1010 @param[in] op CeedOperator to view 1011 @param[in] stream Stream to write; typically stdout/stderr or a file 1012 1013 @return Error code: 0 - success, otherwise - failure 1014 1015 @ref User 1016 **/ 1017 int CeedOperatorView(CeedOperator op, FILE *stream) { 1018 int ierr; 1019 1020 if (op->is_composite) { 1021 fprintf(stream, "Composite CeedOperator\n"); 1022 1023 for (CeedInt i=0; i<op->num_suboperators; i++) { 1024 fprintf(stream, " SubOperator [%d]:\n", i); 1025 ierr = CeedOperatorSingleView(op->sub_operators[i], 1, stream); 1026 CeedChk(ierr); 1027 } 1028 } else { 1029 fprintf(stream, "CeedOperator\n"); 1030 ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr); 1031 } 1032 return CEED_ERROR_SUCCESS; 1033 } 1034 1035 /** 1036 @brief Get the Ceed associated with a CeedOperator 1037 1038 @param op CeedOperator 1039 @param[out] ceed Variable to store Ceed 1040 1041 @return An error code: 0 - success, otherwise - failure 1042 1043 @ref Advanced 1044 **/ 1045 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) { 1046 *ceed = op->ceed; 1047 return CEED_ERROR_SUCCESS; 1048 } 1049 1050 /** 1051 @brief Get the number of elements associated with a CeedOperator 1052 1053 @param op CeedOperator 1054 @param[out] num_elem Variable to store number of elements 1055 1056 @return An error code: 0 - success, otherwise - failure 1057 1058 @ref Advanced 1059 **/ 1060 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) { 1061 if (op->is_composite) 1062 // LCOV_EXCL_START 1063 return CeedError(op->ceed, CEED_ERROR_MINOR, 1064 "Not defined for composite operator"); 1065 // LCOV_EXCL_STOP 1066 1067 *num_elem = op->num_elem; 1068 return CEED_ERROR_SUCCESS; 1069 } 1070 1071 /** 1072 @brief Get the number of quadrature points associated with a CeedOperator 1073 1074 @param op CeedOperator 1075 @param[out] num_qpts Variable to store vector number of quadrature points 1076 1077 @return An error code: 0 - success, otherwise - failure 1078 1079 @ref Advanced 1080 **/ 1081 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) { 1082 if (op->is_composite) 1083 // LCOV_EXCL_START 1084 return CeedError(op->ceed, CEED_ERROR_MINOR, 1085 "Not defined for composite operator"); 1086 // LCOV_EXCL_STOP 1087 1088 *num_qpts = op->num_qpts; 1089 return CEED_ERROR_SUCCESS; 1090 } 1091 1092 /** 1093 @brief Set QFunctionContext field holding a double precision value. 1094 For composite operators, the value is set in all 1095 sub-operator QFunctionContexts that have a matching `field_name`. 1096 1097 @param op CeedOperator 1098 @param field_name Name of field to register 1099 @param value Value to set 1100 1101 @return An error code: 0 - success, otherwise - failure 1102 1103 @ref User 1104 **/ 1105 int CeedOperatorContextSetDouble(CeedOperator op, const char *field_name, 1106 double value) { 1107 return CeedOperatorContextSetGeneric(op, field_name, CEED_CONTEXT_FIELD_DOUBLE, 1108 &value); 1109 } 1110 1111 /** 1112 @brief Set QFunctionContext field holding an int32 value. 1113 For composite operators, the value is set in all 1114 sub-operator QFunctionContexts that have a matching `field_name`. 1115 1116 @param op CeedOperator 1117 @param field_name Name of field to set 1118 @param value Value to set 1119 1120 @return An error code: 0 - success, otherwise - failure 1121 1122 @ref User 1123 **/ 1124 int CeedOperatorContextSetInt32(CeedOperator op, const char *field_name, 1125 int value) { 1126 return CeedOperatorContextSetGeneric(op, field_name, CEED_CONTEXT_FIELD_INT32, 1127 &value); 1128 return CEED_ERROR_SUCCESS; 1129 } 1130 1131 /** 1132 @brief Apply CeedOperator to a vector 1133 1134 This computes the action of the operator on the specified (active) input, 1135 yielding its (active) output. All inputs and outputs must be specified using 1136 CeedOperatorSetField(). 1137 1138 Note: Calling this function asserts that setup is complete 1139 and sets the CeedOperator as immutable. 1140 1141 @param op CeedOperator to apply 1142 @param[in] in CeedVector containing input state or @ref CEED_VECTOR_NONE if 1143 there are no active inputs 1144 @param[out] out CeedVector to store result of applying operator (must be 1145 distinct from @a in) or @ref CEED_VECTOR_NONE if there are no 1146 active outputs 1147 @param request Address of CeedRequest for non-blocking completion, else 1148 @ref CEED_REQUEST_IMMEDIATE 1149 1150 @return An error code: 0 - success, otherwise - failure 1151 1152 @ref User 1153 **/ 1154 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, 1155 CeedRequest *request) { 1156 int ierr; 1157 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1158 1159 if (op->num_elem) { 1160 // Standard Operator 1161 if (op->Apply) { 1162 ierr = op->Apply(op, in, out, request); CeedChk(ierr); 1163 } else { 1164 // Zero all output vectors 1165 CeedQFunction qf = op->qf; 1166 for (CeedInt i=0; i<qf->num_output_fields; i++) { 1167 CeedVector vec = op->output_fields[i]->vec; 1168 if (vec == CEED_VECTOR_ACTIVE) 1169 vec = out; 1170 if (vec != CEED_VECTOR_NONE) { 1171 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 1172 } 1173 } 1174 // Apply 1175 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 1176 } 1177 } else if (op->is_composite) { 1178 // Composite Operator 1179 if (op->ApplyComposite) { 1180 ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr); 1181 } else { 1182 CeedInt num_suboperators; 1183 ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1184 CeedOperator *sub_operators; 1185 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1186 1187 // Zero all output vectors 1188 if (out != CEED_VECTOR_NONE) { 1189 ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr); 1190 } 1191 for (CeedInt i=0; i<num_suboperators; i++) { 1192 for (CeedInt j=0; j<sub_operators[i]->qf->num_output_fields; j++) { 1193 CeedVector vec = sub_operators[i]->output_fields[j]->vec; 1194 if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) { 1195 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 1196 } 1197 } 1198 } 1199 // Apply 1200 for (CeedInt i=0; i<op->num_suboperators; i++) { 1201 ierr = CeedOperatorApplyAdd(op->sub_operators[i], in, out, request); 1202 CeedChk(ierr); 1203 } 1204 } 1205 } 1206 return CEED_ERROR_SUCCESS; 1207 } 1208 1209 /** 1210 @brief Apply CeedOperator to a vector and add result to output vector 1211 1212 This computes the action of the operator on the specified (active) input, 1213 yielding its (active) output. All inputs and outputs must be specified using 1214 CeedOperatorSetField(). 1215 1216 @param op CeedOperator to apply 1217 @param[in] in CeedVector containing input state or NULL if there are no 1218 active inputs 1219 @param[out] out CeedVector to sum in result of applying operator (must be 1220 distinct from @a in) or NULL if there are no active outputs 1221 @param request Address of CeedRequest for non-blocking completion, else 1222 @ref CEED_REQUEST_IMMEDIATE 1223 1224 @return An error code: 0 - success, otherwise - failure 1225 1226 @ref User 1227 **/ 1228 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, 1229 CeedRequest *request) { 1230 int ierr; 1231 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1232 1233 if (op->num_elem) { 1234 // Standard Operator 1235 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 1236 } else if (op->is_composite) { 1237 // Composite Operator 1238 if (op->ApplyAddComposite) { 1239 ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr); 1240 } else { 1241 CeedInt num_suboperators; 1242 ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1243 CeedOperator *sub_operators; 1244 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1245 1246 for (CeedInt i=0; i<num_suboperators; i++) { 1247 ierr = CeedOperatorApplyAdd(sub_operators[i], in, out, request); 1248 CeedChk(ierr); 1249 } 1250 } 1251 } 1252 return CEED_ERROR_SUCCESS; 1253 } 1254 1255 /** 1256 @brief Destroy a CeedOperator 1257 1258 @param op CeedOperator to destroy 1259 1260 @return An error code: 0 - success, otherwise - failure 1261 1262 @ref User 1263 **/ 1264 int CeedOperatorDestroy(CeedOperator *op) { 1265 int ierr; 1266 1267 if (!*op || --(*op)->ref_count > 0) return CEED_ERROR_SUCCESS; 1268 if ((*op)->Destroy) { 1269 ierr = (*op)->Destroy(*op); CeedChk(ierr); 1270 } 1271 ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr); 1272 // Free fields 1273 for (int i=0; i<(*op)->num_fields; i++) 1274 if ((*op)->input_fields[i]) { 1275 if ((*op)->input_fields[i]->elem_restr != CEED_ELEMRESTRICTION_NONE) { 1276 ierr = CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_restr); 1277 CeedChk(ierr); 1278 } 1279 if ((*op)->input_fields[i]->basis != CEED_BASIS_COLLOCATED) { 1280 ierr = CeedBasisDestroy(&(*op)->input_fields[i]->basis); CeedChk(ierr); 1281 } 1282 if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE && 1283 (*op)->input_fields[i]->vec != CEED_VECTOR_NONE ) { 1284 ierr = CeedVectorDestroy(&(*op)->input_fields[i]->vec); CeedChk(ierr); 1285 } 1286 ierr = CeedFree(&(*op)->input_fields[i]->field_name); CeedChk(ierr); 1287 ierr = CeedFree(&(*op)->input_fields[i]); CeedChk(ierr); 1288 } 1289 for (int i=0; i<(*op)->num_fields; i++) 1290 if ((*op)->output_fields[i]) { 1291 ierr = CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_restr); 1292 CeedChk(ierr); 1293 if ((*op)->output_fields[i]->basis != CEED_BASIS_COLLOCATED) { 1294 ierr = CeedBasisDestroy(&(*op)->output_fields[i]->basis); CeedChk(ierr); 1295 } 1296 if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE && 1297 (*op)->output_fields[i]->vec != CEED_VECTOR_NONE ) { 1298 ierr = CeedVectorDestroy(&(*op)->output_fields[i]->vec); CeedChk(ierr); 1299 } 1300 ierr = CeedFree(&(*op)->output_fields[i]->field_name); CeedChk(ierr); 1301 ierr = CeedFree(&(*op)->output_fields[i]); CeedChk(ierr); 1302 } 1303 // Destroy sub_operators 1304 for (int i=0; i<(*op)->num_suboperators; i++) 1305 if ((*op)->sub_operators[i]) { 1306 ierr = CeedOperatorDestroy(&(*op)->sub_operators[i]); CeedChk(ierr); 1307 } 1308 ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr); 1309 ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr); 1310 ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr); 1311 1312 // Destroy fallback 1313 if ((*op)->op_fallback) { 1314 ierr = (*op)->qf_fallback->Destroy((*op)->qf_fallback); CeedChk(ierr); 1315 ierr = CeedFree(&(*op)->qf_fallback); CeedChk(ierr); 1316 ierr = CeedVectorDestroy(&(*op)->op_fallback->qf_assembled); CeedChk(ierr); 1317 ierr = CeedElemRestrictionDestroy(&(*op)->op_fallback->qf_assembled_rstr); 1318 CeedChk(ierr); 1319 ierr = (*op)->op_fallback->Destroy((*op)->op_fallback); CeedChk(ierr); 1320 ierr = CeedFree(&(*op)->op_fallback); CeedChk(ierr); 1321 } 1322 1323 // Destroy QF assembly cache 1324 ierr = CeedVectorDestroy(&(*op)->qf_assembled); CeedChk(ierr); 1325 ierr = CeedElemRestrictionDestroy(&(*op)->qf_assembled_rstr); CeedChk(ierr); 1326 1327 ierr = CeedFree(&(*op)->input_fields); CeedChk(ierr); 1328 ierr = CeedFree(&(*op)->output_fields); CeedChk(ierr); 1329 ierr = CeedFree(&(*op)->sub_operators); CeedChk(ierr); 1330 ierr = CeedFree(op); CeedChk(ierr); 1331 return CEED_ERROR_SUCCESS; 1332 } 1333 1334 /// @} 1335