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 = CeedQFunctionAssemblyDataCreate(ceed, &(*op)->qf_assembled); 583 CeedChk(ierr); 584 ierr = CeedCalloc(CEED_FIELD_MAX, &(*op)->input_fields); CeedChk(ierr); 585 ierr = CeedCalloc(CEED_FIELD_MAX, &(*op)->output_fields); CeedChk(ierr); 586 ierr = ceed->OperatorCreate(*op); CeedChk(ierr); 587 return CEED_ERROR_SUCCESS; 588 } 589 590 /** 591 @brief Create an operator that composes the action of several operators 592 593 @param ceed A Ceed object where the CeedOperator will be created 594 @param[out] op Address of the variable where the newly created 595 Composite CeedOperator will be stored 596 597 @return An error code: 0 - success, otherwise - failure 598 599 @ref User 600 */ 601 int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) { 602 int ierr; 603 604 if (!ceed->CompositeOperatorCreate) { 605 Ceed delegate; 606 ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr); 607 608 if (delegate) { 609 ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr); 610 return CEED_ERROR_SUCCESS; 611 } 612 } 613 614 ierr = CeedCalloc(1, op); CeedChk(ierr); 615 (*op)->ceed = ceed; 616 ierr = CeedReference(ceed); CeedChk(ierr); 617 (*op)->is_composite = true; 618 ierr = CeedCalloc(CEED_COMPOSITE_MAX, &(*op)->sub_operators); CeedChk(ierr); 619 620 if (ceed->CompositeOperatorCreate) { 621 ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr); 622 } 623 return CEED_ERROR_SUCCESS; 624 } 625 626 /** 627 @brief Copy the pointer to a CeedOperator. Both pointers should 628 be destroyed with `CeedOperatorDestroy()`; 629 Note: If `*op_copy` is non-NULL, then it is assumed that 630 `*op_copy` is a pointer to a CeedOperator. This 631 CeedOperator will be destroyed if `*op_copy` is the only 632 reference to this CeedOperator. 633 634 @param op CeedOperator to copy reference to 635 @param[out] op_copy Variable to store copied reference 636 637 @return An error code: 0 - success, otherwise - failure 638 639 @ref User 640 **/ 641 int CeedOperatorReferenceCopy(CeedOperator op, CeedOperator *op_copy) { 642 int ierr; 643 644 ierr = CeedOperatorReference(op); CeedChk(ierr); 645 ierr = CeedOperatorDestroy(op_copy); CeedChk(ierr); 646 *op_copy = op; 647 return CEED_ERROR_SUCCESS; 648 } 649 650 /** 651 @brief Provide a field to a CeedOperator for use by its CeedQFunction 652 653 This function is used to specify both active and passive fields to a 654 CeedOperator. For passive fields, a vector @arg v must be provided. Passive 655 fields can inputs or outputs (updated in-place when operator is applied). 656 657 Active fields must be specified using this function, but their data (in a 658 CeedVector) is passed in CeedOperatorApply(). There can be at most one active 659 input and at most one active output. 660 661 @param op CeedOperator on which to provide the field 662 @param field_name Name of the field (to be matched with the name used by 663 CeedQFunction) 664 @param r CeedElemRestriction 665 @param b CeedBasis in which the field resides or @ref CEED_BASIS_COLLOCATED 666 if collocated with quadrature points 667 @param v CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE 668 if field is active or @ref CEED_VECTOR_NONE if using 669 @ref CEED_EVAL_WEIGHT in the QFunction 670 671 @return An error code: 0 - success, otherwise - failure 672 673 @ref User 674 **/ 675 int CeedOperatorSetField(CeedOperator op, const char *field_name, 676 CeedElemRestriction r, CeedBasis b, CeedVector v) { 677 int ierr; 678 if (op->is_composite) 679 // LCOV_EXCL_START 680 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 681 "Cannot add field to composite operator."); 682 // LCOV_EXCL_STOP 683 if (op->is_immutable) 684 // LCOV_EXCL_START 685 return CeedError(op->ceed, CEED_ERROR_MAJOR, 686 "Operator cannot be changed after set as immutable"); 687 // LCOV_EXCL_STOP 688 if (!r) 689 // LCOV_EXCL_START 690 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 691 "ElemRestriction r for field \"%s\" must be non-NULL.", 692 field_name); 693 // LCOV_EXCL_STOP 694 if (!b) 695 // LCOV_EXCL_START 696 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 697 "Basis b for field \"%s\" must be non-NULL.", 698 field_name); 699 // LCOV_EXCL_STOP 700 if (!v) 701 // LCOV_EXCL_START 702 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 703 "Vector v for field \"%s\" must be non-NULL.", 704 field_name); 705 // LCOV_EXCL_STOP 706 707 CeedInt num_elem; 708 ierr = CeedElemRestrictionGetNumElements(r, &num_elem); CeedChk(ierr); 709 if (r != CEED_ELEMRESTRICTION_NONE && op->has_restriction && 710 op->num_elem != num_elem) 711 // LCOV_EXCL_START 712 return CeedError(op->ceed, CEED_ERROR_DIMENSION, 713 "ElemRestriction with %d elements incompatible with prior " 714 "%d elements", num_elem, op->num_elem); 715 // LCOV_EXCL_STOP 716 717 CeedInt num_qpts = 0; 718 if (b != CEED_BASIS_COLLOCATED) { 719 ierr = CeedBasisGetNumQuadraturePoints(b, &num_qpts); CeedChk(ierr); 720 if (op->num_qpts && op->num_qpts != num_qpts) 721 // LCOV_EXCL_START 722 return CeedError(op->ceed, CEED_ERROR_DIMENSION, 723 "Basis with %d quadrature points " 724 "incompatible with prior %d points", num_qpts, 725 op->num_qpts); 726 // LCOV_EXCL_STOP 727 } 728 CeedQFunctionField qf_field; 729 CeedOperatorField *op_field; 730 for (CeedInt i=0; i<op->qf->num_input_fields; i++) { 731 if (!strcmp(field_name, (*op->qf->input_fields[i]).field_name)) { 732 qf_field = op->qf->input_fields[i]; 733 op_field = &op->input_fields[i]; 734 goto found; 735 } 736 } 737 for (CeedInt i=0; i<op->qf->num_output_fields; i++) { 738 if (!strcmp(field_name, (*op->qf->output_fields[i]).field_name)) { 739 qf_field = op->qf->output_fields[i]; 740 op_field = &op->output_fields[i]; 741 goto found; 742 } 743 } 744 // LCOV_EXCL_START 745 return CeedError(op->ceed, CEED_ERROR_INCOMPLETE, 746 "QFunction has no knowledge of field '%s'", 747 field_name); 748 // LCOV_EXCL_STOP 749 found: 750 ierr = CeedOperatorCheckField(op->ceed, qf_field, r, b); CeedChk(ierr); 751 ierr = CeedCalloc(1, op_field); CeedChk(ierr); 752 753 (*op_field)->vec = v; 754 if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) { 755 ierr = CeedVectorReference(v); CeedChk(ierr); 756 } 757 758 (*op_field)->elem_restr = r; 759 ierr = CeedElemRestrictionReference(r); CeedChk(ierr); 760 if (r != CEED_ELEMRESTRICTION_NONE) { 761 op->num_elem = num_elem; 762 op->has_restriction = true; // Restriction set, but num_elem may be 0 763 } 764 765 (*op_field)->basis = b; 766 if (b != CEED_BASIS_COLLOCATED) { 767 if (!op->num_qpts) { 768 ierr = CeedOperatorSetNumQuadraturePoints(op, num_qpts); CeedChk(ierr); 769 } 770 ierr = CeedBasisReference(b); CeedChk(ierr); 771 } 772 773 op->num_fields += 1; 774 ierr = CeedStringAllocCopy(field_name, (char **)&(*op_field)->field_name); 775 CeedChk(ierr); 776 return CEED_ERROR_SUCCESS; 777 } 778 779 /** 780 @brief Get the CeedOperatorFields of a CeedOperator 781 782 Note: Calling this function asserts that setup is complete 783 and sets the CeedOperator as immutable. 784 785 @param op CeedOperator 786 @param[out] num_input_fields Variable to store number of input fields 787 @param[out] input_fields Variable to store input_fields 788 @param[out] num_output_fields Variable to store number of output fields 789 @param[out] output_fields Variable to store output_fields 790 791 @return An error code: 0 - success, otherwise - failure 792 793 @ref Advanced 794 **/ 795 int CeedOperatorGetFields(CeedOperator op, CeedInt *num_input_fields, 796 CeedOperatorField **input_fields, 797 CeedInt *num_output_fields, 798 CeedOperatorField **output_fields) { 799 int ierr; 800 801 if (op->is_composite) 802 // LCOV_EXCL_START 803 return CeedError(op->ceed, CEED_ERROR_MINOR, 804 "Not defined for composite operator"); 805 // LCOV_EXCL_STOP 806 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 807 808 if (num_input_fields) *num_input_fields = op->qf->num_input_fields; 809 if (input_fields) *input_fields = op->input_fields; 810 if (num_output_fields) *num_output_fields = op->qf->num_output_fields; 811 if (output_fields) *output_fields = op->output_fields; 812 return CEED_ERROR_SUCCESS; 813 } 814 815 /** 816 @brief Get the name of a CeedOperatorField 817 818 @param op_field CeedOperatorField 819 @param[out] field_name Variable to store the field name 820 821 @return An error code: 0 - success, otherwise - failure 822 823 @ref Advanced 824 **/ 825 int CeedOperatorFieldGetName(CeedOperatorField op_field, char **field_name) { 826 *field_name = (char *)op_field->field_name; 827 return CEED_ERROR_SUCCESS; 828 } 829 830 /** 831 @brief Get the CeedElemRestriction of a CeedOperatorField 832 833 @param op_field CeedOperatorField 834 @param[out] rstr Variable to store CeedElemRestriction 835 836 @return An error code: 0 - success, otherwise - failure 837 838 @ref Advanced 839 **/ 840 int CeedOperatorFieldGetElemRestriction(CeedOperatorField op_field, 841 CeedElemRestriction *rstr) { 842 *rstr = op_field->elem_restr; 843 return CEED_ERROR_SUCCESS; 844 } 845 846 /** 847 @brief Get the CeedBasis of a CeedOperatorField 848 849 @param op_field CeedOperatorField 850 @param[out] basis Variable to store CeedBasis 851 852 @return An error code: 0 - success, otherwise - failure 853 854 @ref Advanced 855 **/ 856 int CeedOperatorFieldGetBasis(CeedOperatorField op_field, CeedBasis *basis) { 857 *basis = op_field->basis; 858 return CEED_ERROR_SUCCESS; 859 } 860 861 /** 862 @brief Get the CeedVector of a CeedOperatorField 863 864 @param op_field CeedOperatorField 865 @param[out] vec Variable to store CeedVector 866 867 @return An error code: 0 - success, otherwise - failure 868 869 @ref Advanced 870 **/ 871 int CeedOperatorFieldGetVector(CeedOperatorField op_field, CeedVector *vec) { 872 *vec = op_field->vec; 873 return CEED_ERROR_SUCCESS; 874 } 875 876 /** 877 @brief Add a sub-operator to a composite CeedOperator 878 879 @param[out] composite_op Composite CeedOperator 880 @param sub_op Sub-operator CeedOperator 881 882 @return An error code: 0 - success, otherwise - failure 883 884 @ref User 885 */ 886 int CeedCompositeOperatorAddSub(CeedOperator composite_op, 887 CeedOperator sub_op) { 888 int ierr; 889 890 if (!composite_op->is_composite) 891 // LCOV_EXCL_START 892 return CeedError(composite_op->ceed, CEED_ERROR_MINOR, 893 "CeedOperator is not a composite operator"); 894 // LCOV_EXCL_STOP 895 896 if (composite_op->num_suboperators == CEED_COMPOSITE_MAX) 897 // LCOV_EXCL_START 898 return CeedError(composite_op->ceed, CEED_ERROR_UNSUPPORTED, 899 "Cannot add additional sub_operators"); 900 // LCOV_EXCL_STOP 901 if (composite_op->is_immutable) 902 // LCOV_EXCL_START 903 return CeedError(composite_op->ceed, CEED_ERROR_MAJOR, 904 "Operator cannot be changed after set as immutable"); 905 // LCOV_EXCL_STOP 906 907 composite_op->sub_operators[composite_op->num_suboperators] = sub_op; 908 ierr = CeedOperatorReference(sub_op); CeedChk(ierr); 909 composite_op->num_suboperators++; 910 return CEED_ERROR_SUCCESS; 911 } 912 913 /** 914 @brief Check if a CeedOperator is ready to be used. 915 916 @param[in] op CeedOperator to check 917 918 @return An error code: 0 - success, otherwise - failure 919 920 @ref User 921 **/ 922 int CeedOperatorCheckReady(CeedOperator op) { 923 int ierr; 924 Ceed ceed; 925 ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); 926 927 if (op->is_interface_setup) 928 return CEED_ERROR_SUCCESS; 929 930 CeedQFunction qf = op->qf; 931 if (op->is_composite) { 932 if (!op->num_suboperators) 933 // LCOV_EXCL_START 934 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No sub_operators set"); 935 // LCOV_EXCL_STOP 936 for (CeedInt i = 0; i < op->num_suboperators; i++) { 937 ierr = CeedOperatorCheckReady(op->sub_operators[i]); CeedChk(ierr); 938 } 939 } else { 940 if (op->num_fields == 0) 941 // LCOV_EXCL_START 942 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No operator fields set"); 943 // LCOV_EXCL_STOP 944 if (op->num_fields < qf->num_input_fields + qf->num_output_fields) 945 // LCOV_EXCL_START 946 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set"); 947 // LCOV_EXCL_STOP 948 if (!op->has_restriction) 949 // LCOV_EXCL_START 950 return CeedError(ceed, CEED_ERROR_INCOMPLETE, 951 "At least one restriction required"); 952 // LCOV_EXCL_STOP 953 if (op->num_qpts == 0) 954 // LCOV_EXCL_START 955 return CeedError(ceed, CEED_ERROR_INCOMPLETE, 956 "At least one non-collocated basis is required " 957 "or the number of quadrature points must be set"); 958 // LCOV_EXCL_STOP 959 } 960 961 // Flag as immutable and ready 962 op->is_interface_setup = true; 963 if (op->qf && op->qf != CEED_QFUNCTION_NONE) 964 // LCOV_EXCL_START 965 op->qf->is_immutable = true; 966 // LCOV_EXCL_STOP 967 if (op->dqf && op->dqf != CEED_QFUNCTION_NONE) 968 // LCOV_EXCL_START 969 op->dqf->is_immutable = true; 970 // LCOV_EXCL_STOP 971 if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE) 972 // LCOV_EXCL_START 973 op->dqfT->is_immutable = true; 974 // LCOV_EXCL_STOP 975 return CEED_ERROR_SUCCESS; 976 } 977 978 /** 979 @brief Mark CeedQFunction data as updated and the CeedQFunction as requiring re-assembly. 980 When this function is not used, the CeedQFunction associated with this 981 CeedOperator is re-assembled every time a CeedOperatorLinearAssemble* 982 function is called. When this function is used, the CeedQFunction 983 associated with this CeedOperator is only re-assembled the first time 984 CeedOperatorLinearAssemble* is called after this function is called. 985 The same assembled CeedQFunction data is reused internally until this 986 function is called again. 987 988 @param op CeedOperator 989 990 @return An error code: 0 - success, otherwise - failure 991 992 @ref Advanced 993 **/ 994 int CeedOperatorSetQFunctionUpdated(CeedOperator op) { 995 int ierr; 996 bool is_composite; 997 998 ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 999 if (is_composite) { 1000 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1001 ierr = CeedOperatorSetQFunctionUpdated(op->sub_operators[i]); CeedChk(ierr); 1002 } 1003 } else { 1004 ierr = CeedQFunctionAssemblyDataSetQFunctionUpdated(op->qf_assembled, true); 1005 CeedChk(ierr); 1006 } 1007 1008 return CEED_ERROR_SUCCESS; 1009 } 1010 1011 /** 1012 @brief Set the number of quadrature points associated with a CeedOperator. 1013 This should be used when creating a CeedOperator where every 1014 field has a collocated basis. This function cannot be used for 1015 composite CeedOperators. 1016 1017 @param op CeedOperator 1018 @param num_qpts Number of quadrature points to set 1019 1020 @return An error code: 0 - success, otherwise - failure 1021 1022 @ref Advanced 1023 **/ 1024 int CeedOperatorSetNumQuadraturePoints(CeedOperator op, CeedInt num_qpts) { 1025 if (op->is_composite) 1026 // LCOV_EXCL_START 1027 return CeedError(op->ceed, CEED_ERROR_MINOR, 1028 "Not defined for composite operator"); 1029 // LCOV_EXCL_STOP 1030 if (op->num_qpts) 1031 // LCOV_EXCL_START 1032 return CeedError(op->ceed, CEED_ERROR_MINOR, 1033 "Number of quadrature points already defined"); 1034 // LCOV_EXCL_STOP 1035 if (op->is_immutable) 1036 // LCOV_EXCL_START 1037 return CeedError(op->ceed, CEED_ERROR_MAJOR, 1038 "Operator cannot be changed after set as immutable"); 1039 // LCOV_EXCL_STOP 1040 1041 op->num_qpts = num_qpts; 1042 return CEED_ERROR_SUCCESS; 1043 } 1044 1045 /** 1046 @brief View a CeedOperator 1047 1048 @param[in] op CeedOperator to view 1049 @param[in] stream Stream to write; typically stdout/stderr or a file 1050 1051 @return Error code: 0 - success, otherwise - failure 1052 1053 @ref User 1054 **/ 1055 int CeedOperatorView(CeedOperator op, FILE *stream) { 1056 int ierr; 1057 1058 if (op->is_composite) { 1059 fprintf(stream, "Composite CeedOperator\n"); 1060 1061 for (CeedInt i=0; i<op->num_suboperators; i++) { 1062 fprintf(stream, " SubOperator [%d]:\n", i); 1063 ierr = CeedOperatorSingleView(op->sub_operators[i], 1, stream); 1064 CeedChk(ierr); 1065 } 1066 } else { 1067 fprintf(stream, "CeedOperator\n"); 1068 ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr); 1069 } 1070 return CEED_ERROR_SUCCESS; 1071 } 1072 1073 /** 1074 @brief Get the Ceed associated with a CeedOperator 1075 1076 @param op CeedOperator 1077 @param[out] ceed Variable to store Ceed 1078 1079 @return An error code: 0 - success, otherwise - failure 1080 1081 @ref Advanced 1082 **/ 1083 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) { 1084 *ceed = op->ceed; 1085 return CEED_ERROR_SUCCESS; 1086 } 1087 1088 /** 1089 @brief Get the number of elements associated with a CeedOperator 1090 1091 @param op CeedOperator 1092 @param[out] num_elem Variable to store number of elements 1093 1094 @return An error code: 0 - success, otherwise - failure 1095 1096 @ref Advanced 1097 **/ 1098 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) { 1099 if (op->is_composite) 1100 // LCOV_EXCL_START 1101 return CeedError(op->ceed, CEED_ERROR_MINOR, 1102 "Not defined for composite operator"); 1103 // LCOV_EXCL_STOP 1104 1105 *num_elem = op->num_elem; 1106 return CEED_ERROR_SUCCESS; 1107 } 1108 1109 /** 1110 @brief Get the number of quadrature points associated with a CeedOperator 1111 1112 @param op CeedOperator 1113 @param[out] num_qpts Variable to store vector number of quadrature points 1114 1115 @return An error code: 0 - success, otherwise - failure 1116 1117 @ref Advanced 1118 **/ 1119 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) { 1120 if (op->is_composite) 1121 // LCOV_EXCL_START 1122 return CeedError(op->ceed, CEED_ERROR_MINOR, 1123 "Not defined for composite operator"); 1124 // LCOV_EXCL_STOP 1125 1126 *num_qpts = op->num_qpts; 1127 return CEED_ERROR_SUCCESS; 1128 } 1129 1130 /** 1131 @brief Get label for a registered QFunctionContext field, or `NULL` if no 1132 field has been registered with this `field_name`. 1133 1134 @param[in] op CeedOperator 1135 @param[in] field_name Name of field to retrieve label 1136 @param[out] field_label Variable to field label 1137 1138 @return An error code: 0 - success, otherwise - failure 1139 1140 @ref User 1141 **/ 1142 int CeedOperatorContextGetFieldLabel(CeedOperator op, 1143 const char *field_name, 1144 CeedContextFieldLabel *field_label) { 1145 int ierr; 1146 1147 bool is_composite; 1148 ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1149 if (is_composite) { 1150 // Check if composite label already created 1151 for (CeedInt i=0; i<op->num_context_labels; i++) { 1152 if (!strcmp(op->context_labels[i]->name, field_name)) { 1153 *field_label = op->context_labels[i]; 1154 return CEED_ERROR_SUCCESS; 1155 } 1156 } 1157 1158 // Create composite label if needed 1159 CeedInt num_sub; 1160 CeedOperator *sub_operators; 1161 CeedContextFieldLabel new_field_label; 1162 1163 ierr = CeedCalloc(1, &new_field_label); CeedChk(ierr); 1164 ierr = CeedOperatorGetNumSub(op, &num_sub); CeedChk(ierr); 1165 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1166 ierr = CeedCalloc(num_sub, &new_field_label->sub_labels); CeedChk(ierr); 1167 new_field_label->num_sub_labels = num_sub; 1168 1169 bool label_found = false; 1170 for (CeedInt i=0; i<num_sub; i++) { 1171 if (sub_operators[i]->qf->ctx) { 1172 CeedContextFieldLabel new_field_label_i; 1173 ierr = CeedQFunctionContextGetFieldLabel(sub_operators[i]->qf->ctx, field_name, 1174 &new_field_label_i); CeedChk(ierr); 1175 if (new_field_label_i) { 1176 label_found = true; 1177 new_field_label->sub_labels[i] = new_field_label_i; 1178 new_field_label->name = new_field_label_i->name; 1179 new_field_label->description = new_field_label_i->description; 1180 if (new_field_label->type && 1181 new_field_label->type != new_field_label_i->type) { 1182 // LCOV_EXCL_START 1183 ierr = CeedFree(&new_field_label); CeedChk(ierr); 1184 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 1185 "Incompatible field types on sub-operator contexts. " 1186 "%s != %s", 1187 CeedContextFieldTypes[new_field_label->type], 1188 CeedContextFieldTypes[new_field_label_i->type]); 1189 // LCOV_EXCL_STOP 1190 } else { 1191 new_field_label->type = new_field_label_i->type; 1192 } 1193 if (new_field_label->num_values != 0 && 1194 new_field_label->num_values != new_field_label_i->num_values) { 1195 // LCOV_EXCL_START 1196 ierr = CeedFree(&new_field_label); CeedChk(ierr); 1197 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 1198 "Incompatible field number of values on sub-operator" 1199 " contexts. %ld != %ld", 1200 new_field_label->num_values, new_field_label_i->num_values); 1201 // LCOV_EXCL_STOP 1202 } else { 1203 new_field_label->num_values = new_field_label_i->num_values; 1204 } 1205 } 1206 } 1207 } 1208 if (!label_found) { 1209 // LCOV_EXCL_START 1210 ierr = CeedFree(&new_field_label->sub_labels); CeedChk(ierr); 1211 ierr = CeedFree(&new_field_label); CeedChk(ierr); 1212 *field_label = NULL; 1213 // LCOV_EXCL_STOP 1214 } else { 1215 // Move new composite label to operator 1216 if (op->num_context_labels == 0) { 1217 ierr = CeedCalloc(1, &op->context_labels); CeedChk(ierr); 1218 op->max_context_labels = 1; 1219 } else if (op->num_context_labels == op->max_context_labels) { 1220 ierr = CeedRealloc(2*op->num_context_labels, &op->context_labels); 1221 CeedChk(ierr); 1222 op->max_context_labels *= 2; 1223 } 1224 op->context_labels[op->num_context_labels] = new_field_label; 1225 *field_label = new_field_label; 1226 op->num_context_labels++; 1227 } 1228 1229 return CEED_ERROR_SUCCESS; 1230 } else { 1231 return CeedQFunctionContextGetFieldLabel(op->qf->ctx, field_name, field_label); 1232 } 1233 } 1234 1235 /** 1236 @brief Set QFunctionContext field holding a double precision value. 1237 For composite operators, the value is set in all 1238 sub-operator QFunctionContexts that have a matching `field_name`. 1239 1240 @param op CeedOperator 1241 @param field_label Label of field to register 1242 @param values Values to set 1243 1244 @return An error code: 0 - success, otherwise - failure 1245 1246 @ref User 1247 **/ 1248 int CeedOperatorContextSetDouble(CeedOperator op, 1249 CeedContextFieldLabel field_label, 1250 double *values) { 1251 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, 1252 values); 1253 } 1254 1255 /** 1256 @brief Set QFunctionContext field holding an int32 value. 1257 For composite operators, the value is set in all 1258 sub-operator QFunctionContexts that have a matching `field_name`. 1259 1260 @param op CeedOperator 1261 @param field_label Label of field to set 1262 @param values Values to set 1263 1264 @return An error code: 0 - success, otherwise - failure 1265 1266 @ref User 1267 **/ 1268 int CeedOperatorContextSetInt32(CeedOperator op, 1269 CeedContextFieldLabel field_label, 1270 int *values) { 1271 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_INT32, 1272 values); 1273 } 1274 1275 /** 1276 @brief Apply CeedOperator to a vector 1277 1278 This computes the action of the operator on the specified (active) input, 1279 yielding its (active) output. All inputs and outputs must be specified using 1280 CeedOperatorSetField(). 1281 1282 Note: Calling this function asserts that setup is complete 1283 and sets the CeedOperator as immutable. 1284 1285 @param op CeedOperator to apply 1286 @param[in] in CeedVector containing input state or @ref CEED_VECTOR_NONE if 1287 there are no active inputs 1288 @param[out] out CeedVector to store result of applying operator (must be 1289 distinct from @a in) or @ref CEED_VECTOR_NONE if there are no 1290 active outputs 1291 @param request Address of CeedRequest for non-blocking completion, else 1292 @ref CEED_REQUEST_IMMEDIATE 1293 1294 @return An error code: 0 - success, otherwise - failure 1295 1296 @ref User 1297 **/ 1298 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, 1299 CeedRequest *request) { 1300 int ierr; 1301 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1302 1303 if (op->num_elem) { 1304 // Standard Operator 1305 if (op->Apply) { 1306 ierr = op->Apply(op, in, out, request); CeedChk(ierr); 1307 } else { 1308 // Zero all output vectors 1309 CeedQFunction qf = op->qf; 1310 for (CeedInt i=0; i<qf->num_output_fields; i++) { 1311 CeedVector vec = op->output_fields[i]->vec; 1312 if (vec == CEED_VECTOR_ACTIVE) 1313 vec = out; 1314 if (vec != CEED_VECTOR_NONE) { 1315 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 1316 } 1317 } 1318 // Apply 1319 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 1320 } 1321 } else if (op->is_composite) { 1322 // Composite Operator 1323 if (op->ApplyComposite) { 1324 ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr); 1325 } else { 1326 CeedInt num_suboperators; 1327 ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1328 CeedOperator *sub_operators; 1329 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1330 1331 // Zero all output vectors 1332 if (out != CEED_VECTOR_NONE) { 1333 ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr); 1334 } 1335 for (CeedInt i=0; i<num_suboperators; i++) { 1336 for (CeedInt j=0; j<sub_operators[i]->qf->num_output_fields; j++) { 1337 CeedVector vec = sub_operators[i]->output_fields[j]->vec; 1338 if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) { 1339 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 1340 } 1341 } 1342 } 1343 // Apply 1344 for (CeedInt i=0; i<op->num_suboperators; i++) { 1345 ierr = CeedOperatorApplyAdd(op->sub_operators[i], in, out, request); 1346 CeedChk(ierr); 1347 } 1348 } 1349 } 1350 return CEED_ERROR_SUCCESS; 1351 } 1352 1353 /** 1354 @brief Apply CeedOperator to a vector and add result to output vector 1355 1356 This computes the action of the operator on the specified (active) input, 1357 yielding its (active) output. All inputs and outputs must be specified using 1358 CeedOperatorSetField(). 1359 1360 @param op CeedOperator to apply 1361 @param[in] in CeedVector containing input state or NULL if there are no 1362 active inputs 1363 @param[out] out CeedVector to sum in result of applying operator (must be 1364 distinct from @a in) or NULL if there are no active outputs 1365 @param request Address of CeedRequest for non-blocking completion, else 1366 @ref CEED_REQUEST_IMMEDIATE 1367 1368 @return An error code: 0 - success, otherwise - failure 1369 1370 @ref User 1371 **/ 1372 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, 1373 CeedRequest *request) { 1374 int ierr; 1375 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1376 1377 if (op->num_elem) { 1378 // Standard Operator 1379 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 1380 } else if (op->is_composite) { 1381 // Composite Operator 1382 if (op->ApplyAddComposite) { 1383 ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr); 1384 } else { 1385 CeedInt num_suboperators; 1386 ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1387 CeedOperator *sub_operators; 1388 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1389 1390 for (CeedInt i=0; i<num_suboperators; i++) { 1391 ierr = CeedOperatorApplyAdd(sub_operators[i], in, out, request); 1392 CeedChk(ierr); 1393 } 1394 } 1395 } 1396 return CEED_ERROR_SUCCESS; 1397 } 1398 1399 /** 1400 @brief Destroy a CeedOperator 1401 1402 @param op CeedOperator to destroy 1403 1404 @return An error code: 0 - success, otherwise - failure 1405 1406 @ref User 1407 **/ 1408 int CeedOperatorDestroy(CeedOperator *op) { 1409 int ierr; 1410 1411 if (!*op || --(*op)->ref_count > 0) return CEED_ERROR_SUCCESS; 1412 if ((*op)->Destroy) { 1413 ierr = (*op)->Destroy(*op); CeedChk(ierr); 1414 } 1415 ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr); 1416 // Free fields 1417 for (CeedInt i=0; i<(*op)->num_fields; i++) 1418 if ((*op)->input_fields[i]) { 1419 if ((*op)->input_fields[i]->elem_restr != CEED_ELEMRESTRICTION_NONE) { 1420 ierr = CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_restr); 1421 CeedChk(ierr); 1422 } 1423 if ((*op)->input_fields[i]->basis != CEED_BASIS_COLLOCATED) { 1424 ierr = CeedBasisDestroy(&(*op)->input_fields[i]->basis); CeedChk(ierr); 1425 } 1426 if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE && 1427 (*op)->input_fields[i]->vec != CEED_VECTOR_NONE ) { 1428 ierr = CeedVectorDestroy(&(*op)->input_fields[i]->vec); CeedChk(ierr); 1429 } 1430 ierr = CeedFree(&(*op)->input_fields[i]->field_name); CeedChk(ierr); 1431 ierr = CeedFree(&(*op)->input_fields[i]); CeedChk(ierr); 1432 } 1433 for (CeedInt i=0; i<(*op)->num_fields; i++) 1434 if ((*op)->output_fields[i]) { 1435 ierr = CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_restr); 1436 CeedChk(ierr); 1437 if ((*op)->output_fields[i]->basis != CEED_BASIS_COLLOCATED) { 1438 ierr = CeedBasisDestroy(&(*op)->output_fields[i]->basis); CeedChk(ierr); 1439 } 1440 if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE && 1441 (*op)->output_fields[i]->vec != CEED_VECTOR_NONE ) { 1442 ierr = CeedVectorDestroy(&(*op)->output_fields[i]->vec); CeedChk(ierr); 1443 } 1444 ierr = CeedFree(&(*op)->output_fields[i]->field_name); CeedChk(ierr); 1445 ierr = CeedFree(&(*op)->output_fields[i]); CeedChk(ierr); 1446 } 1447 // Destroy sub_operators 1448 for (CeedInt i=0; i<(*op)->num_suboperators; i++) 1449 if ((*op)->sub_operators[i]) { 1450 ierr = CeedOperatorDestroy(&(*op)->sub_operators[i]); CeedChk(ierr); 1451 } 1452 ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr); 1453 ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr); 1454 ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr); 1455 // Destroy any composite labels 1456 for (CeedInt i=0; i<(*op)->num_context_labels; i++) { 1457 ierr = CeedFree(&(*op)->context_labels[i]->sub_labels); CeedChk(ierr); 1458 ierr = CeedFree(&(*op)->context_labels[i]); CeedChk(ierr); 1459 } 1460 ierr = CeedFree(&(*op)->context_labels); CeedChk(ierr); 1461 1462 // Destroy fallback 1463 if ((*op)->op_fallback) { 1464 ierr = (*op)->qf_fallback->Destroy((*op)->qf_fallback); CeedChk(ierr); 1465 ierr = CeedFree(&(*op)->qf_fallback); CeedChk(ierr); 1466 ierr = (*op)->op_fallback->Destroy((*op)->op_fallback); CeedChk(ierr); 1467 ierr = CeedFree(&(*op)->op_fallback); CeedChk(ierr); 1468 } 1469 1470 // Destroy QF assembly cache 1471 ierr = CeedQFunctionAssemblyDataDestroy(&(*op)->qf_assembled); CeedChk(ierr); 1472 1473 ierr = CeedFree(&(*op)->input_fields); CeedChk(ierr); 1474 ierr = CeedFree(&(*op)->output_fields); CeedChk(ierr); 1475 ierr = CeedFree(&(*op)->sub_operators); CeedChk(ierr); 1476 ierr = CeedFree(op); CeedChk(ierr); 1477 return CEED_ERROR_SUCCESS; 1478 } 1479 1480 /// @} 1481