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 if (new_field_label->type && 1146 new_field_label->type != new_field_label_i->type) { 1147 // LCOV_EXCL_START 1148 ierr = CeedFree(&new_field_label); CeedChk(ierr); 1149 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 1150 "Incompatible field types on sub-operator contexts. " 1151 "%s != %s", 1152 CeedContextFieldTypes[new_field_label->type], 1153 CeedContextFieldTypes[new_field_label_i->type]); 1154 // LCOV_EXCL_STOP 1155 } else { 1156 new_field_label->type = new_field_label_i->type; 1157 } 1158 if (new_field_label->num_values != 0 && 1159 new_field_label->num_values != new_field_label_i->num_values) { 1160 // LCOV_EXCL_START 1161 ierr = CeedFree(&new_field_label); CeedChk(ierr); 1162 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 1163 "Incompatible field number of values on sub-operator" 1164 " contexts. %ld != %ld", 1165 new_field_label->num_values, new_field_label_i->num_values); 1166 // LCOV_EXCL_STOP 1167 } else { 1168 new_field_label->num_values = new_field_label_i->num_values; 1169 } 1170 } 1171 } 1172 } 1173 if (!label_found) { 1174 // LCOV_EXCL_START 1175 ierr = CeedFree(&new_field_label); CeedChk(ierr); 1176 *field_label = NULL; 1177 // LCOV_EXCL_STOP 1178 } else { 1179 // Move new composite label to operator 1180 if (op->num_context_labels == 0) { 1181 ierr = CeedCalloc(1, &op->context_labels); CeedChk(ierr); 1182 op->max_context_labels = 1; 1183 } else if (op->num_context_labels == op->max_context_labels) { 1184 ierr = CeedRealloc(2*op->num_context_labels, &op->context_labels); 1185 CeedChk(ierr); 1186 op->max_context_labels *= 2; 1187 } 1188 op->context_labels[op->num_context_labels] = new_field_label; 1189 *field_label = new_field_label; 1190 op->num_context_labels++; 1191 } 1192 1193 return CEED_ERROR_SUCCESS; 1194 } else { 1195 return CeedQFunctionContextGetFieldLabel(op->qf->ctx, field_name, field_label); 1196 } 1197 } 1198 1199 /** 1200 @brief Set QFunctionContext field holding a double precision value. 1201 For composite operators, the value is set in all 1202 sub-operator QFunctionContexts that have a matching `field_name`. 1203 1204 @param op CeedOperator 1205 @param field_label Label of field to register 1206 @param values Values to set 1207 1208 @return An error code: 0 - success, otherwise - failure 1209 1210 @ref User 1211 **/ 1212 int CeedOperatorContextSetDouble(CeedOperator op, 1213 CeedContextFieldLabel field_label, 1214 double *values) { 1215 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, 1216 values); 1217 } 1218 1219 /** 1220 @brief Set QFunctionContext field holding an int32 value. 1221 For composite operators, the value is set in all 1222 sub-operator QFunctionContexts that have a matching `field_name`. 1223 1224 @param op CeedOperator 1225 @param field_label Label of field to set 1226 @param values Values to set 1227 1228 @return An error code: 0 - success, otherwise - failure 1229 1230 @ref User 1231 **/ 1232 int CeedOperatorContextSetInt32(CeedOperator op, 1233 CeedContextFieldLabel field_label, 1234 int *values) { 1235 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_INT32, 1236 values); 1237 } 1238 1239 /** 1240 @brief Apply CeedOperator to a vector 1241 1242 This computes the action of the operator on the specified (active) input, 1243 yielding its (active) output. All inputs and outputs must be specified using 1244 CeedOperatorSetField(). 1245 1246 Note: Calling this function asserts that setup is complete 1247 and sets the CeedOperator as immutable. 1248 1249 @param op CeedOperator to apply 1250 @param[in] in CeedVector containing input state or @ref CEED_VECTOR_NONE if 1251 there are no active inputs 1252 @param[out] out CeedVector to store result of applying operator (must be 1253 distinct from @a in) or @ref CEED_VECTOR_NONE if there are no 1254 active outputs 1255 @param request Address of CeedRequest for non-blocking completion, else 1256 @ref CEED_REQUEST_IMMEDIATE 1257 1258 @return An error code: 0 - success, otherwise - failure 1259 1260 @ref User 1261 **/ 1262 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, 1263 CeedRequest *request) { 1264 int ierr; 1265 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1266 1267 if (op->num_elem) { 1268 // Standard Operator 1269 if (op->Apply) { 1270 ierr = op->Apply(op, in, out, request); CeedChk(ierr); 1271 } else { 1272 // Zero all output vectors 1273 CeedQFunction qf = op->qf; 1274 for (CeedInt i=0; i<qf->num_output_fields; i++) { 1275 CeedVector vec = op->output_fields[i]->vec; 1276 if (vec == CEED_VECTOR_ACTIVE) 1277 vec = out; 1278 if (vec != CEED_VECTOR_NONE) { 1279 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 1280 } 1281 } 1282 // Apply 1283 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 1284 } 1285 } else if (op->is_composite) { 1286 // Composite Operator 1287 if (op->ApplyComposite) { 1288 ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr); 1289 } else { 1290 CeedInt num_suboperators; 1291 ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1292 CeedOperator *sub_operators; 1293 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1294 1295 // Zero all output vectors 1296 if (out != CEED_VECTOR_NONE) { 1297 ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr); 1298 } 1299 for (CeedInt i=0; i<num_suboperators; i++) { 1300 for (CeedInt j=0; j<sub_operators[i]->qf->num_output_fields; j++) { 1301 CeedVector vec = sub_operators[i]->output_fields[j]->vec; 1302 if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) { 1303 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 1304 } 1305 } 1306 } 1307 // Apply 1308 for (CeedInt i=0; i<op->num_suboperators; i++) { 1309 ierr = CeedOperatorApplyAdd(op->sub_operators[i], in, out, request); 1310 CeedChk(ierr); 1311 } 1312 } 1313 } 1314 return CEED_ERROR_SUCCESS; 1315 } 1316 1317 /** 1318 @brief Apply CeedOperator to a vector and add result to output vector 1319 1320 This computes the action of the operator on the specified (active) input, 1321 yielding its (active) output. All inputs and outputs must be specified using 1322 CeedOperatorSetField(). 1323 1324 @param op CeedOperator to apply 1325 @param[in] in CeedVector containing input state or NULL if there are no 1326 active inputs 1327 @param[out] out CeedVector to sum in result of applying operator (must be 1328 distinct from @a in) or NULL if there are no active outputs 1329 @param request Address of CeedRequest for non-blocking completion, else 1330 @ref CEED_REQUEST_IMMEDIATE 1331 1332 @return An error code: 0 - success, otherwise - failure 1333 1334 @ref User 1335 **/ 1336 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, 1337 CeedRequest *request) { 1338 int ierr; 1339 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1340 1341 if (op->num_elem) { 1342 // Standard Operator 1343 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 1344 } else if (op->is_composite) { 1345 // Composite Operator 1346 if (op->ApplyAddComposite) { 1347 ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr); 1348 } else { 1349 CeedInt num_suboperators; 1350 ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1351 CeedOperator *sub_operators; 1352 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1353 1354 for (CeedInt i=0; i<num_suboperators; i++) { 1355 ierr = CeedOperatorApplyAdd(sub_operators[i], in, out, request); 1356 CeedChk(ierr); 1357 } 1358 } 1359 } 1360 return CEED_ERROR_SUCCESS; 1361 } 1362 1363 /** 1364 @brief Destroy a CeedOperator 1365 1366 @param op CeedOperator to destroy 1367 1368 @return An error code: 0 - success, otherwise - failure 1369 1370 @ref User 1371 **/ 1372 int CeedOperatorDestroy(CeedOperator *op) { 1373 int ierr; 1374 1375 if (!*op || --(*op)->ref_count > 0) return CEED_ERROR_SUCCESS; 1376 if ((*op)->Destroy) { 1377 ierr = (*op)->Destroy(*op); CeedChk(ierr); 1378 } 1379 ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr); 1380 // Free fields 1381 for (CeedInt i=0; i<(*op)->num_fields; i++) 1382 if ((*op)->input_fields[i]) { 1383 if ((*op)->input_fields[i]->elem_restr != CEED_ELEMRESTRICTION_NONE) { 1384 ierr = CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_restr); 1385 CeedChk(ierr); 1386 } 1387 if ((*op)->input_fields[i]->basis != CEED_BASIS_COLLOCATED) { 1388 ierr = CeedBasisDestroy(&(*op)->input_fields[i]->basis); CeedChk(ierr); 1389 } 1390 if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE && 1391 (*op)->input_fields[i]->vec != CEED_VECTOR_NONE ) { 1392 ierr = CeedVectorDestroy(&(*op)->input_fields[i]->vec); CeedChk(ierr); 1393 } 1394 ierr = CeedFree(&(*op)->input_fields[i]->field_name); CeedChk(ierr); 1395 ierr = CeedFree(&(*op)->input_fields[i]); CeedChk(ierr); 1396 } 1397 for (CeedInt i=0; i<(*op)->num_fields; i++) 1398 if ((*op)->output_fields[i]) { 1399 ierr = CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_restr); 1400 CeedChk(ierr); 1401 if ((*op)->output_fields[i]->basis != CEED_BASIS_COLLOCATED) { 1402 ierr = CeedBasisDestroy(&(*op)->output_fields[i]->basis); CeedChk(ierr); 1403 } 1404 if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE && 1405 (*op)->output_fields[i]->vec != CEED_VECTOR_NONE ) { 1406 ierr = CeedVectorDestroy(&(*op)->output_fields[i]->vec); CeedChk(ierr); 1407 } 1408 ierr = CeedFree(&(*op)->output_fields[i]->field_name); CeedChk(ierr); 1409 ierr = CeedFree(&(*op)->output_fields[i]); CeedChk(ierr); 1410 } 1411 // Destroy sub_operators 1412 for (CeedInt i=0; i<(*op)->num_suboperators; i++) 1413 if ((*op)->sub_operators[i]) { 1414 ierr = CeedOperatorDestroy(&(*op)->sub_operators[i]); CeedChk(ierr); 1415 } 1416 ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr); 1417 ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr); 1418 ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr); 1419 // Destroy any composite labels 1420 for (CeedInt i=0; i<(*op)->num_context_labels; i++) { 1421 ierr = CeedFree(&(*op)->context_labels[i]->sub_labels); CeedChk(ierr); 1422 ierr = CeedFree(&(*op)->context_labels[i]); CeedChk(ierr); 1423 } 1424 ierr = CeedFree(&(*op)->context_labels); CeedChk(ierr); 1425 1426 // Destroy fallback 1427 if ((*op)->op_fallback) { 1428 ierr = (*op)->qf_fallback->Destroy((*op)->qf_fallback); CeedChk(ierr); 1429 ierr = CeedFree(&(*op)->qf_fallback); CeedChk(ierr); 1430 ierr = CeedVectorDestroy(&(*op)->op_fallback->qf_assembled); CeedChk(ierr); 1431 ierr = CeedElemRestrictionDestroy(&(*op)->op_fallback->qf_assembled_rstr); 1432 CeedChk(ierr); 1433 ierr = (*op)->op_fallback->Destroy((*op)->op_fallback); CeedChk(ierr); 1434 ierr = CeedFree(&(*op)->op_fallback); CeedChk(ierr); 1435 } 1436 1437 // Destroy QF assembly cache 1438 ierr = CeedVectorDestroy(&(*op)->qf_assembled); CeedChk(ierr); 1439 ierr = CeedElemRestrictionDestroy(&(*op)->qf_assembled_rstr); CeedChk(ierr); 1440 1441 ierr = CeedFree(&(*op)->input_fields); CeedChk(ierr); 1442 ierr = CeedFree(&(*op)->output_fields); CeedChk(ierr); 1443 ierr = CeedFree(&(*op)->sub_operators); CeedChk(ierr); 1444 ierr = CeedFree(op); CeedChk(ierr); 1445 return CEED_ERROR_SUCCESS; 1446 } 1447 1448 /// @} 1449