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