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_label Label 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 CeedContextFieldLabel field_label, CeedContextFieldType field_type, 286 void *value) { 287 int ierr; 288 289 if (!field_label) 290 // LCOV_EXCL_START 291 return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, 292 "Invalid field label"); 293 // LCOV_EXCL_STOP 294 295 bool is_composite = false; 296 ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 297 if (is_composite) { 298 CeedInt num_sub; 299 CeedOperator *sub_operators; 300 301 ierr = CeedOperatorGetNumSub(op, &num_sub); CeedChk(ierr); 302 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 303 if (num_sub != field_label->num_sub_labels) 304 // LCOV_EXCL_START 305 return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, 306 "ContextLabel does not correspond to composite operator.\n" 307 "Use CeedOperatorGetContextFieldLabel()."); 308 // LCOV_EXCL_STOP 309 310 for (CeedInt i = 0; i < num_sub; i++) { 311 // Try every sub-operator, ok if some sub-operators do not have field 312 if (field_label->sub_labels[i] && sub_operators[i]->qf->ctx) { 313 ierr = CeedQFunctionContextSetGeneric(sub_operators[i]->qf->ctx, 314 field_label->sub_labels[i], 315 field_type, value); CeedChk(ierr); 316 } 317 } 318 } else { 319 if (!op->qf->ctx) 320 // LCOV_EXCL_START 321 return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, 322 "QFunction does not have context data"); 323 // LCOV_EXCL_STOP 324 325 ierr = CeedQFunctionContextSetGeneric(op->qf->ctx, field_label, 326 field_type, value); CeedChk(ierr); 327 } 328 329 return CEED_ERROR_SUCCESS; 330 } 331 332 /// @} 333 334 /// ---------------------------------------------------------------------------- 335 /// CeedOperator Backend API 336 /// ---------------------------------------------------------------------------- 337 /// @addtogroup CeedOperatorBackend 338 /// @{ 339 340 /** 341 @brief Get the number of arguments associated with a CeedOperator 342 343 @param op CeedOperator 344 @param[out] num_args Variable to store vector number of arguments 345 346 @return An error code: 0 - success, otherwise - failure 347 348 @ref Backend 349 **/ 350 351 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *num_args) { 352 if (op->is_composite) 353 // LCOV_EXCL_START 354 return CeedError(op->ceed, CEED_ERROR_MINOR, 355 "Not defined for composite operators"); 356 // LCOV_EXCL_STOP 357 358 *num_args = op->num_fields; 359 return CEED_ERROR_SUCCESS; 360 } 361 362 /** 363 @brief Get the setup status of a CeedOperator 364 365 @param op CeedOperator 366 @param[out] is_setup_done Variable to store setup status 367 368 @return An error code: 0 - success, otherwise - failure 369 370 @ref Backend 371 **/ 372 373 int CeedOperatorIsSetupDone(CeedOperator op, bool *is_setup_done) { 374 *is_setup_done = op->is_backend_setup; 375 return CEED_ERROR_SUCCESS; 376 } 377 378 /** 379 @brief Get the QFunction associated with a CeedOperator 380 381 @param op CeedOperator 382 @param[out] qf Variable to store QFunction 383 384 @return An error code: 0 - success, otherwise - failure 385 386 @ref Backend 387 **/ 388 389 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) { 390 if (op->is_composite) 391 // LCOV_EXCL_START 392 return CeedError(op->ceed, CEED_ERROR_MINOR, 393 "Not defined for composite operator"); 394 // LCOV_EXCL_STOP 395 396 *qf = op->qf; 397 return CEED_ERROR_SUCCESS; 398 } 399 400 /** 401 @brief Get a boolean value indicating if the CeedOperator is composite 402 403 @param op CeedOperator 404 @param[out] is_composite Variable to store composite status 405 406 @return An error code: 0 - success, otherwise - failure 407 408 @ref Backend 409 **/ 410 411 int CeedOperatorIsComposite(CeedOperator op, bool *is_composite) { 412 *is_composite = op->is_composite; 413 return CEED_ERROR_SUCCESS; 414 } 415 416 /** 417 @brief Get the number of sub_operators associated with a CeedOperator 418 419 @param op CeedOperator 420 @param[out] num_suboperators Variable to store number of sub_operators 421 422 @return An error code: 0 - success, otherwise - failure 423 424 @ref Backend 425 **/ 426 427 int CeedOperatorGetNumSub(CeedOperator op, CeedInt *num_suboperators) { 428 if (!op->is_composite) 429 // LCOV_EXCL_START 430 return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator"); 431 // LCOV_EXCL_STOP 432 433 *num_suboperators = op->num_suboperators; 434 return CEED_ERROR_SUCCESS; 435 } 436 437 /** 438 @brief Get the list of sub_operators associated with a CeedOperator 439 440 @param op CeedOperator 441 @param[out] sub_operators Variable to store list of sub_operators 442 443 @return An error code: 0 - success, otherwise - failure 444 445 @ref Backend 446 **/ 447 448 int CeedOperatorGetSubList(CeedOperator op, CeedOperator **sub_operators) { 449 if (!op->is_composite) 450 // LCOV_EXCL_START 451 return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator"); 452 // LCOV_EXCL_STOP 453 454 *sub_operators = op->sub_operators; 455 return CEED_ERROR_SUCCESS; 456 } 457 458 /** 459 @brief Get the backend data of a CeedOperator 460 461 @param op CeedOperator 462 @param[out] data Variable to store data 463 464 @return An error code: 0 - success, otherwise - failure 465 466 @ref Backend 467 **/ 468 469 int CeedOperatorGetData(CeedOperator op, void *data) { 470 *(void **)data = op->data; 471 return CEED_ERROR_SUCCESS; 472 } 473 474 /** 475 @brief Set the backend data of a CeedOperator 476 477 @param[out] op CeedOperator 478 @param data Data to set 479 480 @return An error code: 0 - success, otherwise - failure 481 482 @ref Backend 483 **/ 484 485 int CeedOperatorSetData(CeedOperator op, void *data) { 486 op->data = data; 487 return CEED_ERROR_SUCCESS; 488 } 489 490 /** 491 @brief Increment the reference counter for a CeedOperator 492 493 @param op CeedOperator to increment the reference counter 494 495 @return An error code: 0 - success, otherwise - failure 496 497 @ref Backend 498 **/ 499 int CeedOperatorReference(CeedOperator op) { 500 op->ref_count++; 501 return CEED_ERROR_SUCCESS; 502 } 503 504 /** 505 @brief Set the setup flag of a CeedOperator to True 506 507 @param op CeedOperator 508 509 @return An error code: 0 - success, otherwise - failure 510 511 @ref Backend 512 **/ 513 514 int CeedOperatorSetSetupDone(CeedOperator op) { 515 op->is_backend_setup = true; 516 return CEED_ERROR_SUCCESS; 517 } 518 519 /// @} 520 521 /// ---------------------------------------------------------------------------- 522 /// CeedOperator Public API 523 /// ---------------------------------------------------------------------------- 524 /// @addtogroup CeedOperatorUser 525 /// @{ 526 527 /** 528 @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and 529 CeedElemRestriction can be associated with CeedQFunction fields with 530 \ref CeedOperatorSetField. 531 532 @param ceed A Ceed object where the CeedOperator will be created 533 @param qf QFunction defining the action of the operator at quadrature points 534 @param dqf QFunction defining the action of the Jacobian of @a qf (or 535 @ref CEED_QFUNCTION_NONE) 536 @param dqfT QFunction defining the action of the transpose of the Jacobian 537 of @a qf (or @ref CEED_QFUNCTION_NONE) 538 @param[out] op Address of the variable where the newly created 539 CeedOperator will be stored 540 541 @return An error code: 0 - success, otherwise - failure 542 543 @ref User 544 */ 545 int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, 546 CeedQFunction dqfT, CeedOperator *op) { 547 int ierr; 548 549 if (!ceed->OperatorCreate) { 550 Ceed delegate; 551 ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr); 552 553 if (!delegate) 554 // LCOV_EXCL_START 555 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 556 "Backend does not support OperatorCreate"); 557 // LCOV_EXCL_STOP 558 559 ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr); 560 return CEED_ERROR_SUCCESS; 561 } 562 563 if (!qf || qf == CEED_QFUNCTION_NONE) 564 // LCOV_EXCL_START 565 return CeedError(ceed, CEED_ERROR_MINOR, 566 "Operator must have a valid QFunction."); 567 // LCOV_EXCL_STOP 568 ierr = CeedCalloc(1, op); CeedChk(ierr); 569 (*op)->ceed = ceed; 570 ierr = CeedReference(ceed); CeedChk(ierr); 571 (*op)->ref_count = 1; 572 (*op)->qf = qf; 573 ierr = CeedQFunctionReference(qf); CeedChk(ierr); 574 if (dqf && dqf != CEED_QFUNCTION_NONE) { 575 (*op)->dqf = dqf; 576 ierr = CeedQFunctionReference(dqf); CeedChk(ierr); 577 } 578 if (dqfT && dqfT != CEED_QFUNCTION_NONE) { 579 (*op)->dqfT = dqfT; 580 ierr = CeedQFunctionReference(dqfT); CeedChk(ierr); 581 } 582 ierr = CeedCalloc(CEED_FIELD_MAX, &(*op)->input_fields); CeedChk(ierr); 583 ierr = CeedCalloc(CEED_FIELD_MAX, &(*op)->output_fields); CeedChk(ierr); 584 ierr = ceed->OperatorCreate(*op); CeedChk(ierr); 585 return CEED_ERROR_SUCCESS; 586 } 587 588 /** 589 @brief Create an operator that composes the action of several operators 590 591 @param ceed A Ceed object where the CeedOperator will be created 592 @param[out] op Address of the variable where the newly created 593 Composite CeedOperator will be stored 594 595 @return An error code: 0 - success, otherwise - failure 596 597 @ref User 598 */ 599 int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) { 600 int ierr; 601 602 if (!ceed->CompositeOperatorCreate) { 603 Ceed delegate; 604 ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr); 605 606 if (delegate) { 607 ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr); 608 return CEED_ERROR_SUCCESS; 609 } 610 } 611 612 ierr = CeedCalloc(1, op); CeedChk(ierr); 613 (*op)->ceed = ceed; 614 ierr = CeedReference(ceed); CeedChk(ierr); 615 (*op)->is_composite = true; 616 ierr = CeedCalloc(CEED_COMPOSITE_MAX, &(*op)->sub_operators); CeedChk(ierr); 617 618 if (ceed->CompositeOperatorCreate) { 619 ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr); 620 } 621 return CEED_ERROR_SUCCESS; 622 } 623 624 /** 625 @brief Copy the pointer to a CeedOperator. Both pointers should 626 be destroyed with `CeedOperatorDestroy()`; 627 Note: If `*op_copy` is non-NULL, then it is assumed that 628 `*op_copy` is a pointer to a CeedOperator. This 629 CeedOperator will be destroyed if `*op_copy` is the only 630 reference to this CeedOperator. 631 632 @param op CeedOperator to copy reference to 633 @param[out] op_copy Variable to store copied reference 634 635 @return An error code: 0 - success, otherwise - failure 636 637 @ref User 638 **/ 639 int CeedOperatorReferenceCopy(CeedOperator op, CeedOperator *op_copy) { 640 int ierr; 641 642 ierr = CeedOperatorReference(op); CeedChk(ierr); 643 ierr = CeedOperatorDestroy(op_copy); CeedChk(ierr); 644 *op_copy = op; 645 return CEED_ERROR_SUCCESS; 646 } 647 648 /** 649 @brief Provide a field to a CeedOperator for use by its CeedQFunction 650 651 This function is used to specify both active and passive fields to a 652 CeedOperator. For passive fields, a vector @arg v must be provided. Passive 653 fields can inputs or outputs (updated in-place when operator is applied). 654 655 Active fields must be specified using this function, but their data (in a 656 CeedVector) is passed in CeedOperatorApply(). There can be at most one active 657 input and at most one active output. 658 659 @param op CeedOperator on which to provide the field 660 @param field_name Name of the field (to be matched with the name used by 661 CeedQFunction) 662 @param r CeedElemRestriction 663 @param b CeedBasis in which the field resides or @ref CEED_BASIS_COLLOCATED 664 if collocated with quadrature points 665 @param v CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE 666 if field is active or @ref CEED_VECTOR_NONE if using 667 @ref CEED_EVAL_WEIGHT in the QFunction 668 669 @return An error code: 0 - success, otherwise - failure 670 671 @ref User 672 **/ 673 int CeedOperatorSetField(CeedOperator op, const char *field_name, 674 CeedElemRestriction r, CeedBasis b, CeedVector v) { 675 int ierr; 676 if (op->is_composite) 677 // LCOV_EXCL_START 678 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 679 "Cannot add field to composite operator."); 680 // LCOV_EXCL_STOP 681 if (op->is_immutable) 682 // LCOV_EXCL_START 683 return CeedError(op->ceed, CEED_ERROR_MAJOR, 684 "Operator cannot be changed after set as immutable"); 685 // LCOV_EXCL_STOP 686 if (!r) 687 // LCOV_EXCL_START 688 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 689 "ElemRestriction r for field \"%s\" must be non-NULL.", 690 field_name); 691 // LCOV_EXCL_STOP 692 if (!b) 693 // LCOV_EXCL_START 694 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 695 "Basis b for field \"%s\" must be non-NULL.", 696 field_name); 697 // LCOV_EXCL_STOP 698 if (!v) 699 // LCOV_EXCL_START 700 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 701 "Vector v for field \"%s\" must be non-NULL.", 702 field_name); 703 // LCOV_EXCL_STOP 704 705 CeedInt num_elem; 706 ierr = CeedElemRestrictionGetNumElements(r, &num_elem); CeedChk(ierr); 707 if (r != CEED_ELEMRESTRICTION_NONE && op->has_restriction && 708 op->num_elem != num_elem) 709 // LCOV_EXCL_START 710 return CeedError(op->ceed, CEED_ERROR_DIMENSION, 711 "ElemRestriction with %d elements incompatible with prior " 712 "%d elements", num_elem, op->num_elem); 713 // LCOV_EXCL_STOP 714 715 CeedInt num_qpts = 0; 716 if (b != CEED_BASIS_COLLOCATED) { 717 ierr = CeedBasisGetNumQuadraturePoints(b, &num_qpts); CeedChk(ierr); 718 if (op->num_qpts && op->num_qpts != num_qpts) 719 // LCOV_EXCL_START 720 return CeedError(op->ceed, CEED_ERROR_DIMENSION, 721 "Basis with %d quadrature points " 722 "incompatible with prior %d points", num_qpts, 723 op->num_qpts); 724 // LCOV_EXCL_STOP 725 } 726 CeedQFunctionField qf_field; 727 CeedOperatorField *op_field; 728 for (CeedInt i=0; i<op->qf->num_input_fields; i++) { 729 if (!strcmp(field_name, (*op->qf->input_fields[i]).field_name)) { 730 qf_field = op->qf->input_fields[i]; 731 op_field = &op->input_fields[i]; 732 goto found; 733 } 734 } 735 for (CeedInt i=0; i<op->qf->num_output_fields; i++) { 736 if (!strcmp(field_name, (*op->qf->output_fields[i]).field_name)) { 737 qf_field = op->qf->output_fields[i]; 738 op_field = &op->output_fields[i]; 739 goto found; 740 } 741 } 742 // LCOV_EXCL_START 743 return CeedError(op->ceed, CEED_ERROR_INCOMPLETE, 744 "QFunction has no knowledge of field '%s'", 745 field_name); 746 // LCOV_EXCL_STOP 747 found: 748 ierr = CeedOperatorCheckField(op->ceed, qf_field, r, b); CeedChk(ierr); 749 ierr = CeedCalloc(1, op_field); CeedChk(ierr); 750 751 (*op_field)->vec = v; 752 if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) { 753 ierr = CeedVectorReference(v); CeedChk(ierr); 754 } 755 756 (*op_field)->elem_restr = r; 757 ierr = CeedElemRestrictionReference(r); CeedChk(ierr); 758 if (r != CEED_ELEMRESTRICTION_NONE) { 759 op->num_elem = num_elem; 760 op->has_restriction = true; // Restriction set, but num_elem may be 0 761 } 762 763 (*op_field)->basis = b; 764 if (b != CEED_BASIS_COLLOCATED) { 765 if (!op->num_qpts) { 766 ierr = CeedOperatorSetNumQuadraturePoints(op, num_qpts); CeedChk(ierr); 767 } 768 ierr = CeedBasisReference(b); CeedChk(ierr); 769 } 770 771 op->num_fields += 1; 772 ierr = CeedStringAllocCopy(field_name, (char **)&(*op_field)->field_name); 773 CeedChk(ierr); 774 return CEED_ERROR_SUCCESS; 775 } 776 777 /** 778 @brief Get the CeedOperatorFields of a CeedOperator 779 780 Note: Calling this function asserts that setup is complete 781 and sets the CeedOperator as immutable. 782 783 @param op CeedOperator 784 @param[out] num_input_fields Variable to store number of input fields 785 @param[out] input_fields Variable to store input_fields 786 @param[out] num_output_fields Variable to store number of output fields 787 @param[out] output_fields Variable to store output_fields 788 789 @return An error code: 0 - success, otherwise - failure 790 791 @ref Advanced 792 **/ 793 int CeedOperatorGetFields(CeedOperator op, CeedInt *num_input_fields, 794 CeedOperatorField **input_fields, 795 CeedInt *num_output_fields, 796 CeedOperatorField **output_fields) { 797 int ierr; 798 799 if (op->is_composite) 800 // LCOV_EXCL_START 801 return CeedError(op->ceed, CEED_ERROR_MINOR, 802 "Not defined for composite operator"); 803 // LCOV_EXCL_STOP 804 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 805 806 if (num_input_fields) *num_input_fields = op->qf->num_input_fields; 807 if (input_fields) *input_fields = op->input_fields; 808 if (num_output_fields) *num_output_fields = op->qf->num_output_fields; 809 if (output_fields) *output_fields = op->output_fields; 810 return CEED_ERROR_SUCCESS; 811 } 812 813 /** 814 @brief Get the name of a CeedOperatorField 815 816 @param op_field CeedOperatorField 817 @param[out] field_name Variable to store the field name 818 819 @return An error code: 0 - success, otherwise - failure 820 821 @ref Advanced 822 **/ 823 int CeedOperatorFieldGetName(CeedOperatorField op_field, char **field_name) { 824 *field_name = (char *)op_field->field_name; 825 return CEED_ERROR_SUCCESS; 826 } 827 828 /** 829 @brief Get the CeedElemRestriction of a CeedOperatorField 830 831 @param op_field CeedOperatorField 832 @param[out] rstr Variable to store CeedElemRestriction 833 834 @return An error code: 0 - success, otherwise - failure 835 836 @ref Advanced 837 **/ 838 int CeedOperatorFieldGetElemRestriction(CeedOperatorField op_field, 839 CeedElemRestriction *rstr) { 840 *rstr = op_field->elem_restr; 841 return CEED_ERROR_SUCCESS; 842 } 843 844 /** 845 @brief Get the CeedBasis of a CeedOperatorField 846 847 @param op_field CeedOperatorField 848 @param[out] basis Variable to store CeedBasis 849 850 @return An error code: 0 - success, otherwise - failure 851 852 @ref Advanced 853 **/ 854 int CeedOperatorFieldGetBasis(CeedOperatorField op_field, CeedBasis *basis) { 855 *basis = op_field->basis; 856 return CEED_ERROR_SUCCESS; 857 } 858 859 /** 860 @brief Get the CeedVector of a CeedOperatorField 861 862 @param op_field CeedOperatorField 863 @param[out] vec Variable to store CeedVector 864 865 @return An error code: 0 - success, otherwise - failure 866 867 @ref Advanced 868 **/ 869 int CeedOperatorFieldGetVector(CeedOperatorField op_field, CeedVector *vec) { 870 *vec = op_field->vec; 871 return CEED_ERROR_SUCCESS; 872 } 873 874 /** 875 @brief Add a sub-operator to a composite CeedOperator 876 877 @param[out] composite_op Composite CeedOperator 878 @param sub_op Sub-operator CeedOperator 879 880 @return An error code: 0 - success, otherwise - failure 881 882 @ref User 883 */ 884 int CeedCompositeOperatorAddSub(CeedOperator composite_op, 885 CeedOperator sub_op) { 886 int ierr; 887 888 if (!composite_op->is_composite) 889 // LCOV_EXCL_START 890 return CeedError(composite_op->ceed, CEED_ERROR_MINOR, 891 "CeedOperator is not a composite operator"); 892 // LCOV_EXCL_STOP 893 894 if (composite_op->num_suboperators == CEED_COMPOSITE_MAX) 895 // LCOV_EXCL_START 896 return CeedError(composite_op->ceed, CEED_ERROR_UNSUPPORTED, 897 "Cannot add additional sub_operators"); 898 // LCOV_EXCL_STOP 899 if (composite_op->is_immutable) 900 // LCOV_EXCL_START 901 return CeedError(composite_op->ceed, CEED_ERROR_MAJOR, 902 "Operator cannot be changed after set as immutable"); 903 // LCOV_EXCL_STOP 904 905 composite_op->sub_operators[composite_op->num_suboperators] = sub_op; 906 ierr = CeedOperatorReference(sub_op); CeedChk(ierr); 907 composite_op->num_suboperators++; 908 return CEED_ERROR_SUCCESS; 909 } 910 911 /** 912 @brief Check if a CeedOperator is ready to be used. 913 914 @param[in] op CeedOperator to check 915 916 @return An error code: 0 - success, otherwise - failure 917 918 @ref User 919 **/ 920 int CeedOperatorCheckReady(CeedOperator op) { 921 int ierr; 922 Ceed ceed; 923 ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); 924 925 if (op->is_interface_setup) 926 return CEED_ERROR_SUCCESS; 927 928 CeedQFunction qf = op->qf; 929 if (op->is_composite) { 930 if (!op->num_suboperators) 931 // LCOV_EXCL_START 932 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No sub_operators set"); 933 // LCOV_EXCL_STOP 934 for (CeedInt i = 0; i < op->num_suboperators; i++) { 935 ierr = CeedOperatorCheckReady(op->sub_operators[i]); CeedChk(ierr); 936 } 937 } else { 938 if (op->num_fields == 0) 939 // LCOV_EXCL_START 940 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No operator fields set"); 941 // LCOV_EXCL_STOP 942 if (op->num_fields < qf->num_input_fields + qf->num_output_fields) 943 // LCOV_EXCL_START 944 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set"); 945 // LCOV_EXCL_STOP 946 if (!op->has_restriction) 947 // LCOV_EXCL_START 948 return CeedError(ceed, CEED_ERROR_INCOMPLETE, 949 "At least one restriction required"); 950 // LCOV_EXCL_STOP 951 if (op->num_qpts == 0) 952 // LCOV_EXCL_START 953 return CeedError(ceed, CEED_ERROR_INCOMPLETE, 954 "At least one non-collocated basis is required " 955 "or the number of quadrature points must be set"); 956 // LCOV_EXCL_STOP 957 } 958 959 // Flag as immutable and ready 960 op->is_interface_setup = true; 961 if (op->qf && op->qf != CEED_QFUNCTION_NONE) 962 // LCOV_EXCL_START 963 op->qf->is_immutable = true; 964 // LCOV_EXCL_STOP 965 if (op->dqf && op->dqf != CEED_QFUNCTION_NONE) 966 // LCOV_EXCL_START 967 op->dqf->is_immutable = true; 968 // LCOV_EXCL_STOP 969 if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE) 970 // LCOV_EXCL_START 971 op->dqfT->is_immutable = true; 972 // LCOV_EXCL_STOP 973 return CEED_ERROR_SUCCESS; 974 } 975 976 /** 977 @brief Set the number of quadrature points associated with a CeedOperator. 978 This should be used when creating a CeedOperator where every 979 field has a collocated basis. This function cannot be used for 980 composite CeedOperators. 981 982 @param op CeedOperator 983 @param num_qpts Number of quadrature points to set 984 985 @return An error code: 0 - success, otherwise - failure 986 987 @ref Advanced 988 **/ 989 int CeedOperatorSetNumQuadraturePoints(CeedOperator op, CeedInt num_qpts) { 990 if (op->is_composite) 991 // LCOV_EXCL_START 992 return CeedError(op->ceed, CEED_ERROR_MINOR, 993 "Not defined for composite operator"); 994 // LCOV_EXCL_STOP 995 if (op->num_qpts) 996 // LCOV_EXCL_START 997 return CeedError(op->ceed, CEED_ERROR_MINOR, 998 "Number of quadrature points already defined"); 999 // LCOV_EXCL_STOP 1000 if (op->is_immutable) 1001 // LCOV_EXCL_START 1002 return CeedError(op->ceed, CEED_ERROR_MAJOR, 1003 "Operator cannot be changed after set as immutable"); 1004 // LCOV_EXCL_STOP 1005 1006 op->num_qpts = num_qpts; 1007 return CEED_ERROR_SUCCESS; 1008 } 1009 1010 /** 1011 @brief View a CeedOperator 1012 1013 @param[in] op CeedOperator to view 1014 @param[in] stream Stream to write; typically stdout/stderr or a file 1015 1016 @return Error code: 0 - success, otherwise - failure 1017 1018 @ref User 1019 **/ 1020 int CeedOperatorView(CeedOperator op, FILE *stream) { 1021 int ierr; 1022 1023 if (op->is_composite) { 1024 fprintf(stream, "Composite CeedOperator\n"); 1025 1026 for (CeedInt i=0; i<op->num_suboperators; i++) { 1027 fprintf(stream, " SubOperator [%d]:\n", i); 1028 ierr = CeedOperatorSingleView(op->sub_operators[i], 1, stream); 1029 CeedChk(ierr); 1030 } 1031 } else { 1032 fprintf(stream, "CeedOperator\n"); 1033 ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr); 1034 } 1035 return CEED_ERROR_SUCCESS; 1036 } 1037 1038 /** 1039 @brief Get the Ceed associated with a CeedOperator 1040 1041 @param op CeedOperator 1042 @param[out] ceed Variable to store Ceed 1043 1044 @return An error code: 0 - success, otherwise - failure 1045 1046 @ref Advanced 1047 **/ 1048 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) { 1049 *ceed = op->ceed; 1050 return CEED_ERROR_SUCCESS; 1051 } 1052 1053 /** 1054 @brief Get the number of elements associated with a CeedOperator 1055 1056 @param op CeedOperator 1057 @param[out] num_elem Variable to store number of elements 1058 1059 @return An error code: 0 - success, otherwise - failure 1060 1061 @ref Advanced 1062 **/ 1063 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) { 1064 if (op->is_composite) 1065 // LCOV_EXCL_START 1066 return CeedError(op->ceed, CEED_ERROR_MINOR, 1067 "Not defined for composite operator"); 1068 // LCOV_EXCL_STOP 1069 1070 *num_elem = op->num_elem; 1071 return CEED_ERROR_SUCCESS; 1072 } 1073 1074 /** 1075 @brief Get the number of quadrature points associated with a CeedOperator 1076 1077 @param op CeedOperator 1078 @param[out] num_qpts Variable to store vector number of quadrature points 1079 1080 @return An error code: 0 - success, otherwise - failure 1081 1082 @ref Advanced 1083 **/ 1084 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) { 1085 if (op->is_composite) 1086 // LCOV_EXCL_START 1087 return CeedError(op->ceed, CEED_ERROR_MINOR, 1088 "Not defined for composite operator"); 1089 // LCOV_EXCL_STOP 1090 1091 *num_qpts = op->num_qpts; 1092 return CEED_ERROR_SUCCESS; 1093 } 1094 1095 /** 1096 @brief Get label for a registered QFunctionContext field, or `NULL` if no 1097 field has been registered with this `field_name`. 1098 1099 @param[in] op CeedOperator 1100 @param[in] field_name Name of field to retrieve label 1101 @param[out] field_label Variable to field label 1102 1103 @return An error code: 0 - success, otherwise - failure 1104 1105 @ref User 1106 **/ 1107 int CeedOperatorContextGetFieldLabel(CeedOperator op, 1108 const char *field_name, 1109 CeedContextFieldLabel *field_label) { 1110 int ierr; 1111 1112 bool is_composite; 1113 ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1114 if (is_composite) { 1115 // Check if composite label already created 1116 for (CeedInt i=0; i<op->num_context_labels; i++) { 1117 if (!strcmp(op->context_labels[i]->name, field_name)) { 1118 *field_label = op->context_labels[i]; 1119 return CEED_ERROR_SUCCESS; 1120 } 1121 } 1122 1123 // Create composite label if needed 1124 CeedInt num_sub; 1125 CeedOperator *sub_operators; 1126 CeedContextFieldLabel new_field_label; 1127 1128 ierr = CeedCalloc(1, &new_field_label); CeedChk(ierr); 1129 ierr = CeedOperatorGetNumSub(op, &num_sub); CeedChk(ierr); 1130 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1131 ierr = CeedCalloc(num_sub, &new_field_label->sub_labels); CeedChk(ierr); 1132 new_field_label->num_sub_labels = num_sub; 1133 1134 bool label_found = false; 1135 for (CeedInt i=0; i<num_sub; i++) { 1136 if (sub_operators[i]->qf->ctx) { 1137 CeedContextFieldLabel new_field_label_i; 1138 ierr = CeedQFunctionContextGetFieldLabel(sub_operators[i]->qf->ctx, field_name, 1139 &new_field_label_i); CeedChk(ierr); 1140 if (new_field_label_i) { 1141 label_found = true; 1142 new_field_label->sub_labels[i] = new_field_label_i; 1143 new_field_label->name = new_field_label_i->name; 1144 new_field_label->description = new_field_label_i->description; 1145 } 1146 } 1147 } 1148 if (!label_found) { 1149 // LCOV_EXCL_START 1150 ierr = CeedFree(&new_field_label); CeedChk(ierr); 1151 *field_label = NULL; 1152 // LCOV_EXCL_STOP 1153 } else { 1154 // Move new composite label to operator 1155 if (op->num_context_labels == 0) { 1156 ierr = CeedCalloc(1, &op->context_labels); CeedChk(ierr); 1157 op->max_context_labels = 1; 1158 } else if (op->num_context_labels == op->max_context_labels) { 1159 ierr = CeedRealloc(2*op->num_context_labels, &op->context_labels); 1160 CeedChk(ierr); 1161 op->max_context_labels *= 2; 1162 } 1163 op->context_labels[op->num_context_labels] = new_field_label; 1164 *field_label = new_field_label; 1165 op->num_context_labels++; 1166 } 1167 1168 return CEED_ERROR_SUCCESS; 1169 } else { 1170 return CeedQFunctionContextGetFieldLabel(op->qf->ctx, field_name, field_label); 1171 } 1172 } 1173 1174 /** 1175 @brief Set QFunctionContext field holding a double precision value. 1176 For composite operators, the value is set in all 1177 sub-operator QFunctionContexts that have a matching `field_name`. 1178 1179 @param op CeedOperator 1180 @param field_label Label of field to register 1181 @param value Value to set 1182 1183 @return An error code: 0 - success, otherwise - failure 1184 1185 @ref User 1186 **/ 1187 int CeedOperatorContextSetDouble(CeedOperator op, 1188 CeedContextFieldLabel field_label, 1189 double value) { 1190 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, 1191 &value); 1192 } 1193 1194 /** 1195 @brief Set QFunctionContext field holding an int32 value. 1196 For composite operators, the value is set in all 1197 sub-operator QFunctionContexts that have a matching `field_name`. 1198 1199 @param op CeedOperator 1200 @param field_label Label of field to set 1201 @param value Value to set 1202 1203 @return An error code: 0 - success, otherwise - failure 1204 1205 @ref User 1206 **/ 1207 int CeedOperatorContextSetInt32(CeedOperator op, 1208 CeedContextFieldLabel field_label, 1209 int value) { 1210 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_INT32, 1211 &value); 1212 } 1213 1214 /** 1215 @brief Apply CeedOperator to a vector 1216 1217 This computes the action of the operator on the specified (active) input, 1218 yielding its (active) output. All inputs and outputs must be specified using 1219 CeedOperatorSetField(). 1220 1221 Note: Calling this function asserts that setup is complete 1222 and sets the CeedOperator as immutable. 1223 1224 @param op CeedOperator to apply 1225 @param[in] in CeedVector containing input state or @ref CEED_VECTOR_NONE if 1226 there are no active inputs 1227 @param[out] out CeedVector to store result of applying operator (must be 1228 distinct from @a in) or @ref CEED_VECTOR_NONE if there are no 1229 active outputs 1230 @param request Address of CeedRequest for non-blocking completion, else 1231 @ref CEED_REQUEST_IMMEDIATE 1232 1233 @return An error code: 0 - success, otherwise - failure 1234 1235 @ref User 1236 **/ 1237 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, 1238 CeedRequest *request) { 1239 int ierr; 1240 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1241 1242 if (op->num_elem) { 1243 // Standard Operator 1244 if (op->Apply) { 1245 ierr = op->Apply(op, in, out, request); CeedChk(ierr); 1246 } else { 1247 // Zero all output vectors 1248 CeedQFunction qf = op->qf; 1249 for (CeedInt i=0; i<qf->num_output_fields; i++) { 1250 CeedVector vec = op->output_fields[i]->vec; 1251 if (vec == CEED_VECTOR_ACTIVE) 1252 vec = out; 1253 if (vec != CEED_VECTOR_NONE) { 1254 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 1255 } 1256 } 1257 // Apply 1258 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 1259 } 1260 } else if (op->is_composite) { 1261 // Composite Operator 1262 if (op->ApplyComposite) { 1263 ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr); 1264 } else { 1265 CeedInt num_suboperators; 1266 ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1267 CeedOperator *sub_operators; 1268 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1269 1270 // Zero all output vectors 1271 if (out != CEED_VECTOR_NONE) { 1272 ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr); 1273 } 1274 for (CeedInt i=0; i<num_suboperators; i++) { 1275 for (CeedInt j=0; j<sub_operators[i]->qf->num_output_fields; j++) { 1276 CeedVector vec = sub_operators[i]->output_fields[j]->vec; 1277 if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) { 1278 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 1279 } 1280 } 1281 } 1282 // Apply 1283 for (CeedInt i=0; i<op->num_suboperators; i++) { 1284 ierr = CeedOperatorApplyAdd(op->sub_operators[i], in, out, request); 1285 CeedChk(ierr); 1286 } 1287 } 1288 } 1289 return CEED_ERROR_SUCCESS; 1290 } 1291 1292 /** 1293 @brief Apply CeedOperator to a vector and add result to output vector 1294 1295 This computes the action of the operator on the specified (active) input, 1296 yielding its (active) output. All inputs and outputs must be specified using 1297 CeedOperatorSetField(). 1298 1299 @param op CeedOperator to apply 1300 @param[in] in CeedVector containing input state or NULL if there are no 1301 active inputs 1302 @param[out] out CeedVector to sum in result of applying operator (must be 1303 distinct from @a in) or NULL if there are no active outputs 1304 @param request Address of CeedRequest for non-blocking completion, else 1305 @ref CEED_REQUEST_IMMEDIATE 1306 1307 @return An error code: 0 - success, otherwise - failure 1308 1309 @ref User 1310 **/ 1311 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, 1312 CeedRequest *request) { 1313 int ierr; 1314 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1315 1316 if (op->num_elem) { 1317 // Standard Operator 1318 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 1319 } else if (op->is_composite) { 1320 // Composite Operator 1321 if (op->ApplyAddComposite) { 1322 ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr); 1323 } else { 1324 CeedInt num_suboperators; 1325 ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1326 CeedOperator *sub_operators; 1327 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1328 1329 for (CeedInt i=0; i<num_suboperators; i++) { 1330 ierr = CeedOperatorApplyAdd(sub_operators[i], in, out, request); 1331 CeedChk(ierr); 1332 } 1333 } 1334 } 1335 return CEED_ERROR_SUCCESS; 1336 } 1337 1338 /** 1339 @brief Destroy a CeedOperator 1340 1341 @param op CeedOperator to destroy 1342 1343 @return An error code: 0 - success, otherwise - failure 1344 1345 @ref User 1346 **/ 1347 int CeedOperatorDestroy(CeedOperator *op) { 1348 int ierr; 1349 1350 if (!*op || --(*op)->ref_count > 0) return CEED_ERROR_SUCCESS; 1351 if ((*op)->Destroy) { 1352 ierr = (*op)->Destroy(*op); CeedChk(ierr); 1353 } 1354 ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr); 1355 // Free fields 1356 for (CeedInt i=0; i<(*op)->num_fields; i++) 1357 if ((*op)->input_fields[i]) { 1358 if ((*op)->input_fields[i]->elem_restr != CEED_ELEMRESTRICTION_NONE) { 1359 ierr = CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_restr); 1360 CeedChk(ierr); 1361 } 1362 if ((*op)->input_fields[i]->basis != CEED_BASIS_COLLOCATED) { 1363 ierr = CeedBasisDestroy(&(*op)->input_fields[i]->basis); CeedChk(ierr); 1364 } 1365 if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE && 1366 (*op)->input_fields[i]->vec != CEED_VECTOR_NONE ) { 1367 ierr = CeedVectorDestroy(&(*op)->input_fields[i]->vec); CeedChk(ierr); 1368 } 1369 ierr = CeedFree(&(*op)->input_fields[i]->field_name); CeedChk(ierr); 1370 ierr = CeedFree(&(*op)->input_fields[i]); CeedChk(ierr); 1371 } 1372 for (CeedInt i=0; i<(*op)->num_fields; i++) 1373 if ((*op)->output_fields[i]) { 1374 ierr = CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_restr); 1375 CeedChk(ierr); 1376 if ((*op)->output_fields[i]->basis != CEED_BASIS_COLLOCATED) { 1377 ierr = CeedBasisDestroy(&(*op)->output_fields[i]->basis); CeedChk(ierr); 1378 } 1379 if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE && 1380 (*op)->output_fields[i]->vec != CEED_VECTOR_NONE ) { 1381 ierr = CeedVectorDestroy(&(*op)->output_fields[i]->vec); CeedChk(ierr); 1382 } 1383 ierr = CeedFree(&(*op)->output_fields[i]->field_name); CeedChk(ierr); 1384 ierr = CeedFree(&(*op)->output_fields[i]); CeedChk(ierr); 1385 } 1386 // Destroy sub_operators 1387 for (CeedInt i=0; i<(*op)->num_suboperators; i++) 1388 if ((*op)->sub_operators[i]) { 1389 ierr = CeedOperatorDestroy(&(*op)->sub_operators[i]); CeedChk(ierr); 1390 } 1391 ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr); 1392 ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr); 1393 ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr); 1394 // Destroy any composite labels 1395 for (CeedInt i=0; i<(*op)->num_context_labels; i++) { 1396 ierr = CeedFree(&(*op)->context_labels[i]->sub_labels); CeedChk(ierr); 1397 ierr = CeedFree(&(*op)->context_labels[i]); CeedChk(ierr); 1398 } 1399 ierr = CeedFree(&(*op)->context_labels); CeedChk(ierr); 1400 1401 // Destroy fallback 1402 if ((*op)->op_fallback) { 1403 ierr = (*op)->qf_fallback->Destroy((*op)->qf_fallback); CeedChk(ierr); 1404 ierr = CeedFree(&(*op)->qf_fallback); CeedChk(ierr); 1405 ierr = CeedVectorDestroy(&(*op)->op_fallback->qf_assembled); CeedChk(ierr); 1406 ierr = CeedElemRestrictionDestroy(&(*op)->op_fallback->qf_assembled_rstr); 1407 CeedChk(ierr); 1408 ierr = (*op)->op_fallback->Destroy((*op)->op_fallback); CeedChk(ierr); 1409 ierr = CeedFree(&(*op)->op_fallback); CeedChk(ierr); 1410 } 1411 1412 // Destroy QF assembly cache 1413 ierr = CeedVectorDestroy(&(*op)->qf_assembled); CeedChk(ierr); 1414 ierr = CeedElemRestrictionDestroy(&(*op)->qf_assembled_rstr); CeedChk(ierr); 1415 1416 ierr = CeedFree(&(*op)->input_fields); CeedChk(ierr); 1417 ierr = CeedFree(&(*op)->output_fields); CeedChk(ierr); 1418 ierr = CeedFree(&(*op)->sub_operators); CeedChk(ierr); 1419 ierr = CeedFree(op); CeedChk(ierr); 1420 return CEED_ERROR_SUCCESS; 1421 } 1422 1423 /// @} 1424