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