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 CeedVector and at most one active output CeedVector passed to 657 CeedOperatorApply(). 658 659 @param op CeedOperator on which to provide the field 660 @param field_name Name of the field (to be matched with the name used by 661 CeedQFunction) 662 @param r CeedElemRestriction 663 @param b CeedBasis in which the field resides or @ref CEED_BASIS_COLLOCATED 664 if collocated with quadrature points 665 @param v CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE 666 if field is active or @ref CEED_VECTOR_NONE if using 667 @ref CEED_EVAL_WEIGHT in the QFunction 668 669 @return An error code: 0 - success, otherwise - failure 670 671 @ref User 672 **/ 673 int CeedOperatorSetField(CeedOperator op, const char *field_name, 674 CeedElemRestriction r, CeedBasis b, CeedVector v) { 675 int ierr; 676 if (op->is_composite) 677 // LCOV_EXCL_START 678 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 679 "Cannot add field to composite operator."); 680 // LCOV_EXCL_STOP 681 if (op->is_immutable) 682 // LCOV_EXCL_START 683 return CeedError(op->ceed, CEED_ERROR_MAJOR, 684 "Operator cannot be changed after set as immutable"); 685 // LCOV_EXCL_STOP 686 if (!r) 687 // LCOV_EXCL_START 688 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 689 "ElemRestriction r for field \"%s\" must be non-NULL.", 690 field_name); 691 // LCOV_EXCL_STOP 692 if (!b) 693 // LCOV_EXCL_START 694 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 695 "Basis b for field \"%s\" must be non-NULL.", 696 field_name); 697 // LCOV_EXCL_STOP 698 if (!v) 699 // LCOV_EXCL_START 700 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 701 "Vector v for field \"%s\" must be non-NULL.", 702 field_name); 703 // LCOV_EXCL_STOP 704 705 CeedInt num_elem; 706 ierr = CeedElemRestrictionGetNumElements(r, &num_elem); CeedChk(ierr); 707 if (r != CEED_ELEMRESTRICTION_NONE && op->has_restriction && 708 op->num_elem != num_elem) 709 // LCOV_EXCL_START 710 return CeedError(op->ceed, CEED_ERROR_DIMENSION, 711 "ElemRestriction with %d elements incompatible with prior " 712 "%d elements", num_elem, op->num_elem); 713 // LCOV_EXCL_STOP 714 715 CeedInt num_qpts = 0; 716 if (b != CEED_BASIS_COLLOCATED) { 717 ierr = CeedBasisGetNumQuadraturePoints(b, &num_qpts); CeedChk(ierr); 718 if (op->num_qpts && op->num_qpts != num_qpts) 719 // LCOV_EXCL_START 720 return CeedError(op->ceed, CEED_ERROR_DIMENSION, 721 "Basis with %d quadrature points " 722 "incompatible with prior %d points", num_qpts, 723 op->num_qpts); 724 // LCOV_EXCL_STOP 725 } 726 CeedQFunctionField qf_field; 727 CeedOperatorField *op_field; 728 bool is_input = true; 729 for (CeedInt i=0; i<op->qf->num_input_fields; i++) { 730 if (!strcmp(field_name, (*op->qf->input_fields[i]).field_name)) { 731 qf_field = op->qf->input_fields[i]; 732 op_field = &op->input_fields[i]; 733 goto found; 734 } 735 } 736 is_input = false; 737 for (CeedInt i=0; i<op->qf->num_output_fields; i++) { 738 if (!strcmp(field_name, (*op->qf->output_fields[i]).field_name)) { 739 qf_field = op->qf->output_fields[i]; 740 op_field = &op->output_fields[i]; 741 goto found; 742 } 743 } 744 // LCOV_EXCL_START 745 return CeedError(op->ceed, CEED_ERROR_INCOMPLETE, 746 "QFunction has no knowledge of field '%s'", 747 field_name); 748 // LCOV_EXCL_STOP 749 found: 750 ierr = CeedOperatorCheckField(op->ceed, qf_field, r, b); CeedChk(ierr); 751 ierr = CeedCalloc(1, op_field); CeedChk(ierr); 752 753 if (v == CEED_VECTOR_ACTIVE) { 754 CeedSize l_size; 755 ierr = CeedElemRestrictionGetLVectorSize(r, &l_size); CeedChk(ierr); 756 if (is_input) { 757 if (op->input_size == -1) op->input_size = l_size; 758 if (l_size != op->input_size) 759 // LCOV_EXCL_START 760 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 761 "LVector size %td does not match previous size %td", 762 l_size, op->input_size); 763 // LCOV_EXCL_STOP 764 } else { 765 if (op->output_size == -1) op->output_size = l_size; 766 if (l_size != op->output_size) 767 // LCOV_EXCL_START 768 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 769 "LVector size %td does not match previous size %td", 770 l_size, op->output_size); 771 // LCOV_EXCL_STOP 772 } 773 } 774 775 (*op_field)->vec = v; 776 if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) { 777 ierr = CeedVectorReference(v); CeedChk(ierr); 778 } 779 780 (*op_field)->elem_restr = r; 781 ierr = CeedElemRestrictionReference(r); CeedChk(ierr); 782 if (r != CEED_ELEMRESTRICTION_NONE) { 783 op->num_elem = num_elem; 784 op->has_restriction = true; // Restriction set, but num_elem may be 0 785 } 786 787 (*op_field)->basis = b; 788 if (b != CEED_BASIS_COLLOCATED) { 789 if (!op->num_qpts) { 790 ierr = CeedOperatorSetNumQuadraturePoints(op, num_qpts); CeedChk(ierr); 791 } 792 ierr = CeedBasisReference(b); CeedChk(ierr); 793 } 794 795 op->num_fields += 1; 796 ierr = CeedStringAllocCopy(field_name, (char **)&(*op_field)->field_name); 797 CeedChk(ierr); 798 return CEED_ERROR_SUCCESS; 799 } 800 801 /** 802 @brief Get the CeedOperatorFields of a CeedOperator 803 804 Note: Calling this function asserts that setup is complete 805 and sets the CeedOperator as immutable. 806 807 @param op CeedOperator 808 @param[out] num_input_fields Variable to store number of input fields 809 @param[out] input_fields Variable to store input_fields 810 @param[out] num_output_fields Variable to store number of output fields 811 @param[out] output_fields Variable to store output_fields 812 813 @return An error code: 0 - success, otherwise - failure 814 815 @ref Advanced 816 **/ 817 int CeedOperatorGetFields(CeedOperator op, CeedInt *num_input_fields, 818 CeedOperatorField **input_fields, 819 CeedInt *num_output_fields, 820 CeedOperatorField **output_fields) { 821 int ierr; 822 823 if (op->is_composite) 824 // LCOV_EXCL_START 825 return CeedError(op->ceed, CEED_ERROR_MINOR, 826 "Not defined for composite operator"); 827 // LCOV_EXCL_STOP 828 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 829 830 if (num_input_fields) *num_input_fields = op->qf->num_input_fields; 831 if (input_fields) *input_fields = op->input_fields; 832 if (num_output_fields) *num_output_fields = op->qf->num_output_fields; 833 if (output_fields) *output_fields = op->output_fields; 834 return CEED_ERROR_SUCCESS; 835 } 836 837 /** 838 @brief Get the name of a CeedOperatorField 839 840 @param op_field CeedOperatorField 841 @param[out] field_name Variable to store the field name 842 843 @return An error code: 0 - success, otherwise - failure 844 845 @ref Advanced 846 **/ 847 int CeedOperatorFieldGetName(CeedOperatorField op_field, char **field_name) { 848 *field_name = (char *)op_field->field_name; 849 return CEED_ERROR_SUCCESS; 850 } 851 852 /** 853 @brief Get the CeedElemRestriction of a CeedOperatorField 854 855 @param op_field CeedOperatorField 856 @param[out] rstr Variable to store CeedElemRestriction 857 858 @return An error code: 0 - success, otherwise - failure 859 860 @ref Advanced 861 **/ 862 int CeedOperatorFieldGetElemRestriction(CeedOperatorField op_field, 863 CeedElemRestriction *rstr) { 864 *rstr = op_field->elem_restr; 865 return CEED_ERROR_SUCCESS; 866 } 867 868 /** 869 @brief Get the CeedBasis of a CeedOperatorField 870 871 @param op_field CeedOperatorField 872 @param[out] basis Variable to store CeedBasis 873 874 @return An error code: 0 - success, otherwise - failure 875 876 @ref Advanced 877 **/ 878 int CeedOperatorFieldGetBasis(CeedOperatorField op_field, CeedBasis *basis) { 879 *basis = op_field->basis; 880 return CEED_ERROR_SUCCESS; 881 } 882 883 /** 884 @brief Get the CeedVector of a CeedOperatorField 885 886 @param op_field CeedOperatorField 887 @param[out] vec Variable to store CeedVector 888 889 @return An error code: 0 - success, otherwise - failure 890 891 @ref Advanced 892 **/ 893 int CeedOperatorFieldGetVector(CeedOperatorField op_field, CeedVector *vec) { 894 *vec = op_field->vec; 895 return CEED_ERROR_SUCCESS; 896 } 897 898 /** 899 @brief Add a sub-operator to a composite CeedOperator 900 901 @param[out] composite_op Composite CeedOperator 902 @param sub_op Sub-operator CeedOperator 903 904 @return An error code: 0 - success, otherwise - failure 905 906 @ref User 907 */ 908 int CeedCompositeOperatorAddSub(CeedOperator composite_op, 909 CeedOperator sub_op) { 910 int ierr; 911 912 if (!composite_op->is_composite) 913 // LCOV_EXCL_START 914 return CeedError(composite_op->ceed, CEED_ERROR_MINOR, 915 "CeedOperator is not a composite operator"); 916 // LCOV_EXCL_STOP 917 918 if (composite_op->num_suboperators == CEED_COMPOSITE_MAX) 919 // LCOV_EXCL_START 920 return CeedError(composite_op->ceed, CEED_ERROR_UNSUPPORTED, 921 "Cannot add additional sub-operators"); 922 // LCOV_EXCL_STOP 923 if (composite_op->is_immutable) 924 // LCOV_EXCL_START 925 return CeedError(composite_op->ceed, CEED_ERROR_MAJOR, 926 "Operator cannot be changed after set as immutable"); 927 // LCOV_EXCL_STOP 928 929 { 930 CeedSize input_size, output_size; 931 ierr = CeedOperatorGetActiveVectorLengths(sub_op, &input_size, &output_size); 932 CeedChk(ierr); 933 if (composite_op->input_size == -1) composite_op->input_size = input_size; 934 if (composite_op->output_size == -1) composite_op->output_size = output_size; 935 // Note, a size of -1 means no active vector restriction set, so no incompatibility 936 if ((input_size != -1 && input_size != composite_op->input_size) || 937 (output_size != -1 && output_size != composite_op->output_size)) 938 // LCOV_EXCL_START 939 return CeedError(composite_op->ceed, CEED_ERROR_MAJOR, 940 "Sub-operators must have compatible dimensions; " 941 "composite operator of shape (%td, %td) not compatible with " 942 "sub-operator of shape (%td, %td)", 943 composite_op->input_size, composite_op->output_size, input_size, output_size); 944 // LCOV_EXCL_STOP 945 } 946 947 composite_op->sub_operators[composite_op->num_suboperators] = sub_op; 948 ierr = CeedOperatorReference(sub_op); CeedChk(ierr); 949 composite_op->num_suboperators++; 950 return CEED_ERROR_SUCCESS; 951 } 952 953 /** 954 @brief Check if a CeedOperator is ready to be used. 955 956 @param[in] op CeedOperator to check 957 958 @return An error code: 0 - success, otherwise - failure 959 960 @ref User 961 **/ 962 int CeedOperatorCheckReady(CeedOperator op) { 963 int ierr; 964 Ceed ceed; 965 ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); 966 967 if (op->is_interface_setup) 968 return CEED_ERROR_SUCCESS; 969 970 CeedQFunction qf = op->qf; 971 if (op->is_composite) { 972 if (!op->num_suboperators) 973 // LCOV_EXCL_START 974 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No sub_operators set"); 975 // LCOV_EXCL_STOP 976 for (CeedInt i = 0; i < op->num_suboperators; i++) { 977 ierr = CeedOperatorCheckReady(op->sub_operators[i]); CeedChk(ierr); 978 } 979 // Sub-operators could be modified after adding to composite operator 980 // Need to verify no lvec incompatibility from any changes 981 CeedSize input_size, output_size; 982 ierr = CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size); 983 CeedChk(ierr); 984 } else { 985 if (op->num_fields == 0) 986 // LCOV_EXCL_START 987 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No operator fields set"); 988 // LCOV_EXCL_STOP 989 if (op->num_fields < qf->num_input_fields + qf->num_output_fields) 990 // LCOV_EXCL_START 991 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set"); 992 // LCOV_EXCL_STOP 993 if (!op->has_restriction) 994 // LCOV_EXCL_START 995 return CeedError(ceed, CEED_ERROR_INCOMPLETE, 996 "At least one restriction required"); 997 // LCOV_EXCL_STOP 998 if (op->num_qpts == 0) 999 // LCOV_EXCL_START 1000 return CeedError(ceed, CEED_ERROR_INCOMPLETE, 1001 "At least one non-collocated basis is required " 1002 "or the number of quadrature points must be set"); 1003 // LCOV_EXCL_STOP 1004 } 1005 1006 // Flag as immutable and ready 1007 op->is_interface_setup = true; 1008 if (op->qf && op->qf != CEED_QFUNCTION_NONE) 1009 // LCOV_EXCL_START 1010 op->qf->is_immutable = true; 1011 // LCOV_EXCL_STOP 1012 if (op->dqf && op->dqf != CEED_QFUNCTION_NONE) 1013 // LCOV_EXCL_START 1014 op->dqf->is_immutable = true; 1015 // LCOV_EXCL_STOP 1016 if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE) 1017 // LCOV_EXCL_START 1018 op->dqfT->is_immutable = true; 1019 // LCOV_EXCL_STOP 1020 return CEED_ERROR_SUCCESS; 1021 } 1022 1023 /** 1024 @brief Get vector lengths for the active input and/or output vectors of a CeedOperator. 1025 Note: Lengths of -1 indicate that the CeedOperator does not have an 1026 active input and/or output. 1027 1028 @param[in] op CeedOperator 1029 @param[out] input_size Variable to store active input vector length, or NULL 1030 @param[out] output_size Variable to store active output vector length, or NULL 1031 1032 @return An error code: 0 - success, otherwise - failure 1033 1034 @ref User 1035 **/ 1036 int CeedOperatorGetActiveVectorLengths(CeedOperator op, CeedSize *input_size, 1037 CeedSize *output_size) { 1038 int ierr; 1039 bool is_composite; 1040 1041 if (input_size) *input_size = op->input_size; 1042 if (output_size) *output_size = op->output_size; 1043 1044 ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1045 if (is_composite && (op->input_size == -1 || op->output_size == -1)) { 1046 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1047 CeedSize sub_input_size, sub_output_size; 1048 ierr = CeedOperatorGetActiveVectorLengths(op->sub_operators[i], 1049 &sub_input_size, &sub_output_size); CeedChk(ierr); 1050 if (op->input_size == -1) op->input_size = sub_input_size; 1051 if (op->output_size == -1) op->output_size = sub_output_size; 1052 // Note, a size of -1 means no active vector restriction set, so no incompatibility 1053 if ((sub_input_size != -1 && sub_input_size != op->input_size) || 1054 (sub_output_size != -1 && sub_output_size != op->output_size)) 1055 // LCOV_EXCL_START 1056 return CeedError(op->ceed, CEED_ERROR_MAJOR, 1057 "Sub-operators must have compatible dimensions; " 1058 "composite operator of shape (%td, %td) not compatible with " 1059 "sub-operator of shape (%td, %td)", 1060 op->input_size, op->output_size, input_size, output_size); 1061 // LCOV_EXCL_STOP 1062 } 1063 } 1064 1065 return CEED_ERROR_SUCCESS; 1066 } 1067 1068 /** 1069 @brief Set reuse of CeedQFunction data in CeedOperatorLinearAssemble* functions. 1070 When `reuse_assembly_data = false` (default), the CeedQFunction associated 1071 with this CeedOperator is re-assembled every time a `CeedOperatorLinearAssemble*` 1072 function is called. 1073 When `reuse_assembly_data = true`, the CeedQFunction associated with 1074 this CeedOperator is reused between calls to 1075 `CeedOperatorSetQFunctionAssemblyDataUpdated`. 1076 1077 @param[in] op CeedOperator 1078 @param[in] reuse_assembly_data Boolean flag setting assembly data reuse 1079 1080 @return An error code: 0 - success, otherwise - failure 1081 1082 @ref Advanced 1083 **/ 1084 int CeedOperatorSetQFunctionAssemblyReuse(CeedOperator op, 1085 bool reuse_assembly_data) { 1086 int ierr; 1087 bool is_composite; 1088 1089 ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1090 if (is_composite) { 1091 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1092 ierr = CeedOperatorSetQFunctionAssemblyReuse(op->sub_operators[i], 1093 reuse_assembly_data); CeedChk(ierr); 1094 } 1095 } else { 1096 ierr = CeedQFunctionAssemblyDataSetReuse(op->qf_assembled, reuse_assembly_data); 1097 CeedChk(ierr); 1098 } 1099 1100 return CEED_ERROR_SUCCESS; 1101 } 1102 1103 /** 1104 @brief Mark CeedQFunction data as updated and the CeedQFunction as requiring re-assembly. 1105 1106 @param[in] op CeedOperator 1107 @param[in] needs_data_update Boolean flag setting assembly data reuse 1108 1109 @return An error code: 0 - success, otherwise - failure 1110 1111 @ref Advanced 1112 **/ 1113 int CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(CeedOperator op, 1114 bool needs_data_update) { 1115 int ierr; 1116 bool is_composite; 1117 1118 ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1119 if (is_composite) { 1120 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1121 ierr = CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(op->sub_operators[i], 1122 needs_data_update); CeedChk(ierr); 1123 } 1124 } else { 1125 ierr = CeedQFunctionAssemblyDataSetUpdateNeeded(op->qf_assembled, 1126 needs_data_update); 1127 CeedChk(ierr); 1128 } 1129 1130 return CEED_ERROR_SUCCESS; 1131 } 1132 1133 /** 1134 @brief Set the number of quadrature points associated with a CeedOperator. 1135 This should be used when creating a CeedOperator where every 1136 field has a collocated basis. This function cannot be used for 1137 composite CeedOperators. 1138 1139 @param op CeedOperator 1140 @param num_qpts Number of quadrature points to set 1141 1142 @return An error code: 0 - success, otherwise - failure 1143 1144 @ref Advanced 1145 **/ 1146 int CeedOperatorSetNumQuadraturePoints(CeedOperator op, CeedInt num_qpts) { 1147 if (op->is_composite) 1148 // LCOV_EXCL_START 1149 return CeedError(op->ceed, CEED_ERROR_MINOR, 1150 "Not defined for composite operator"); 1151 // LCOV_EXCL_STOP 1152 if (op->num_qpts) 1153 // LCOV_EXCL_START 1154 return CeedError(op->ceed, CEED_ERROR_MINOR, 1155 "Number of quadrature points already defined"); 1156 // LCOV_EXCL_STOP 1157 if (op->is_immutable) 1158 // LCOV_EXCL_START 1159 return CeedError(op->ceed, CEED_ERROR_MAJOR, 1160 "Operator cannot be changed after set as immutable"); 1161 // LCOV_EXCL_STOP 1162 1163 op->num_qpts = num_qpts; 1164 return CEED_ERROR_SUCCESS; 1165 } 1166 1167 /** 1168 @brief View a CeedOperator 1169 1170 @param[in] op CeedOperator to view 1171 @param[in] stream Stream to write; typically stdout/stderr or a file 1172 1173 @return Error code: 0 - success, otherwise - failure 1174 1175 @ref User 1176 **/ 1177 int CeedOperatorView(CeedOperator op, FILE *stream) { 1178 int ierr; 1179 1180 if (op->is_composite) { 1181 fprintf(stream, "Composite CeedOperator\n"); 1182 1183 for (CeedInt i=0; i<op->num_suboperators; i++) { 1184 fprintf(stream, " SubOperator [%d]:\n", i); 1185 ierr = CeedOperatorSingleView(op->sub_operators[i], 1, stream); 1186 CeedChk(ierr); 1187 } 1188 } else { 1189 fprintf(stream, "CeedOperator\n"); 1190 ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr); 1191 } 1192 return CEED_ERROR_SUCCESS; 1193 } 1194 1195 /** 1196 @brief Get the Ceed associated with a CeedOperator 1197 1198 @param op CeedOperator 1199 @param[out] ceed Variable to store Ceed 1200 1201 @return An error code: 0 - success, otherwise - failure 1202 1203 @ref Advanced 1204 **/ 1205 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) { 1206 *ceed = op->ceed; 1207 return CEED_ERROR_SUCCESS; 1208 } 1209 1210 /** 1211 @brief Get the number of elements associated with a CeedOperator 1212 1213 @param op CeedOperator 1214 @param[out] num_elem Variable to store number of elements 1215 1216 @return An error code: 0 - success, otherwise - failure 1217 1218 @ref Advanced 1219 **/ 1220 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) { 1221 if (op->is_composite) 1222 // LCOV_EXCL_START 1223 return CeedError(op->ceed, CEED_ERROR_MINOR, 1224 "Not defined for composite operator"); 1225 // LCOV_EXCL_STOP 1226 1227 *num_elem = op->num_elem; 1228 return CEED_ERROR_SUCCESS; 1229 } 1230 1231 /** 1232 @brief Get the number of quadrature points associated with a CeedOperator 1233 1234 @param op CeedOperator 1235 @param[out] num_qpts Variable to store vector number of quadrature points 1236 1237 @return An error code: 0 - success, otherwise - failure 1238 1239 @ref Advanced 1240 **/ 1241 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) { 1242 if (op->is_composite) 1243 // LCOV_EXCL_START 1244 return CeedError(op->ceed, CEED_ERROR_MINOR, 1245 "Not defined for composite operator"); 1246 // LCOV_EXCL_STOP 1247 1248 *num_qpts = op->num_qpts; 1249 return CEED_ERROR_SUCCESS; 1250 } 1251 1252 /** 1253 @brief Estimate number of FLOPs required to apply CeedOperator on the active vector 1254 1255 @param op Operator to estimate FLOPs for 1256 @param flops Address of variable to hold FLOPs estimate 1257 1258 @ref Backend 1259 **/ 1260 int CeedOperatorGetFlopsEstimate(CeedOperator op, CeedSize *flops) { 1261 int ierr; 1262 bool is_composite; 1263 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1264 1265 *flops = 0; 1266 ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1267 if (is_composite) { 1268 CeedInt num_suboperators; 1269 ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1270 CeedOperator *sub_operators; 1271 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1272 1273 // FLOPs for each suboperator 1274 for (CeedInt i = 0; i < num_suboperators; i++) { 1275 CeedSize suboperator_flops; 1276 ierr = CeedOperatorGetFlopsEstimate(sub_operators[i], &suboperator_flops); 1277 CeedChk(ierr); 1278 *flops += suboperator_flops; 1279 } 1280 } else { 1281 CeedInt num_input_fields, num_output_fields; 1282 CeedOperatorField *input_fields, *output_fields; 1283 1284 ierr = CeedOperatorGetFields(op, &num_input_fields, &input_fields, 1285 &num_output_fields, &output_fields); CeedChk(ierr); 1286 1287 CeedInt num_elem = 0; 1288 ierr = CeedOperatorGetNumElements(op, &num_elem); CeedChk(ierr); 1289 // Input FLOPs 1290 for (CeedInt i = 0; i < num_input_fields; i++) { 1291 if (input_fields[i]->vec == CEED_VECTOR_ACTIVE) { 1292 CeedSize restr_flops, basis_flops; 1293 1294 ierr = CeedElemRestrictionGetFlopsEstimate(input_fields[i]->elem_restr, 1295 CEED_NOTRANSPOSE, &restr_flops); CeedChk(ierr); 1296 *flops += restr_flops; 1297 ierr = CeedBasisGetFlopsEstimate(input_fields[i]->basis, CEED_NOTRANSPOSE, 1298 op->qf->input_fields[i]->eval_mode, &basis_flops); CeedChk(ierr); 1299 *flops += basis_flops * num_elem; 1300 } 1301 } 1302 // QF FLOPs 1303 CeedInt num_qpts; 1304 CeedSize qf_flops; 1305 ierr = CeedOperatorGetNumQuadraturePoints(op, &num_qpts); CeedChk(ierr); 1306 ierr = CeedQFunctionGetFlopsEstimate(op->qf, &qf_flops); CeedChk(ierr); 1307 *flops += num_elem * num_qpts * qf_flops; 1308 // Output FLOPs 1309 for (CeedInt i = 0; i < num_output_fields; i++) { 1310 if (output_fields[i]->vec == CEED_VECTOR_ACTIVE) { 1311 CeedSize restr_flops, basis_flops; 1312 1313 ierr = CeedElemRestrictionGetFlopsEstimate(output_fields[i]->elem_restr, 1314 CEED_TRANSPOSE, &restr_flops); CeedChk(ierr); 1315 *flops += restr_flops; 1316 ierr = CeedBasisGetFlopsEstimate(output_fields[i]->basis, CEED_TRANSPOSE, 1317 op->qf->output_fields[i]->eval_mode, &basis_flops); CeedChk(ierr); 1318 *flops += basis_flops * num_elem; 1319 } 1320 } 1321 } 1322 1323 return CEED_ERROR_SUCCESS; 1324 } 1325 1326 /** 1327 @brief Get label for a registered QFunctionContext field, or `NULL` if no 1328 field has been registered with this `field_name`. 1329 1330 @param[in] op CeedOperator 1331 @param[in] field_name Name of field to retrieve label 1332 @param[out] field_label Variable to field label 1333 1334 @return An error code: 0 - success, otherwise - failure 1335 1336 @ref User 1337 **/ 1338 int CeedOperatorContextGetFieldLabel(CeedOperator op, 1339 const char *field_name, 1340 CeedContextFieldLabel *field_label) { 1341 int ierr; 1342 1343 bool is_composite; 1344 ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1345 if (is_composite) { 1346 // Check if composite label already created 1347 for (CeedInt i=0; i<op->num_context_labels; i++) { 1348 if (!strcmp(op->context_labels[i]->name, field_name)) { 1349 *field_label = op->context_labels[i]; 1350 return CEED_ERROR_SUCCESS; 1351 } 1352 } 1353 1354 // Create composite label if needed 1355 CeedInt num_sub; 1356 CeedOperator *sub_operators; 1357 CeedContextFieldLabel new_field_label; 1358 1359 ierr = CeedCalloc(1, &new_field_label); CeedChk(ierr); 1360 ierr = CeedOperatorGetNumSub(op, &num_sub); CeedChk(ierr); 1361 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1362 ierr = CeedCalloc(num_sub, &new_field_label->sub_labels); CeedChk(ierr); 1363 new_field_label->num_sub_labels = num_sub; 1364 1365 bool label_found = false; 1366 for (CeedInt i=0; i<num_sub; i++) { 1367 if (sub_operators[i]->qf->ctx) { 1368 CeedContextFieldLabel new_field_label_i; 1369 ierr = CeedQFunctionContextGetFieldLabel(sub_operators[i]->qf->ctx, field_name, 1370 &new_field_label_i); CeedChk(ierr); 1371 if (new_field_label_i) { 1372 label_found = true; 1373 new_field_label->sub_labels[i] = new_field_label_i; 1374 new_field_label->name = new_field_label_i->name; 1375 new_field_label->description = new_field_label_i->description; 1376 if (new_field_label->type && 1377 new_field_label->type != new_field_label_i->type) { 1378 // LCOV_EXCL_START 1379 ierr = CeedFree(&new_field_label); CeedChk(ierr); 1380 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 1381 "Incompatible field types on sub-operator contexts. " 1382 "%s != %s", 1383 CeedContextFieldTypes[new_field_label->type], 1384 CeedContextFieldTypes[new_field_label_i->type]); 1385 // LCOV_EXCL_STOP 1386 } else { 1387 new_field_label->type = new_field_label_i->type; 1388 } 1389 if (new_field_label->num_values != 0 && 1390 new_field_label->num_values != new_field_label_i->num_values) { 1391 // LCOV_EXCL_START 1392 ierr = CeedFree(&new_field_label); CeedChk(ierr); 1393 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 1394 "Incompatible field number of values on sub-operator" 1395 " contexts. %ld != %ld", 1396 new_field_label->num_values, new_field_label_i->num_values); 1397 // LCOV_EXCL_STOP 1398 } else { 1399 new_field_label->num_values = new_field_label_i->num_values; 1400 } 1401 } 1402 } 1403 } 1404 if (!label_found) { 1405 // LCOV_EXCL_START 1406 ierr = CeedFree(&new_field_label->sub_labels); CeedChk(ierr); 1407 ierr = CeedFree(&new_field_label); CeedChk(ierr); 1408 *field_label = NULL; 1409 // LCOV_EXCL_STOP 1410 } else { 1411 // Move new composite label to operator 1412 if (op->num_context_labels == 0) { 1413 ierr = CeedCalloc(1, &op->context_labels); CeedChk(ierr); 1414 op->max_context_labels = 1; 1415 } else if (op->num_context_labels == op->max_context_labels) { 1416 ierr = CeedRealloc(2*op->num_context_labels, &op->context_labels); 1417 CeedChk(ierr); 1418 op->max_context_labels *= 2; 1419 } 1420 op->context_labels[op->num_context_labels] = new_field_label; 1421 *field_label = new_field_label; 1422 op->num_context_labels++; 1423 } 1424 1425 return CEED_ERROR_SUCCESS; 1426 } else { 1427 return CeedQFunctionContextGetFieldLabel(op->qf->ctx, field_name, field_label); 1428 } 1429 } 1430 1431 /** 1432 @brief Set QFunctionContext field holding a double precision value. 1433 For composite operators, the value is set in all 1434 sub-operator QFunctionContexts that have a matching `field_name`. 1435 1436 @param op CeedOperator 1437 @param field_label Label of field to register 1438 @param values Values to set 1439 1440 @return An error code: 0 - success, otherwise - failure 1441 1442 @ref User 1443 **/ 1444 int CeedOperatorContextSetDouble(CeedOperator op, 1445 CeedContextFieldLabel field_label, 1446 double *values) { 1447 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, 1448 values); 1449 } 1450 1451 /** 1452 @brief Set QFunctionContext field holding an int32 value. 1453 For composite operators, the value is set in all 1454 sub-operator QFunctionContexts that have a matching `field_name`. 1455 1456 @param op CeedOperator 1457 @param field_label Label of field to set 1458 @param values Values to set 1459 1460 @return An error code: 0 - success, otherwise - failure 1461 1462 @ref User 1463 **/ 1464 int CeedOperatorContextSetInt32(CeedOperator op, 1465 CeedContextFieldLabel field_label, 1466 int *values) { 1467 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_INT32, 1468 values); 1469 } 1470 1471 /** 1472 @brief Apply CeedOperator to a vector 1473 1474 This computes the action of the operator on the specified (active) input, 1475 yielding its (active) output. All inputs and outputs must be specified using 1476 CeedOperatorSetField(). 1477 1478 Note: Calling this function asserts that setup is complete 1479 and sets the CeedOperator as immutable. 1480 1481 @param op CeedOperator to apply 1482 @param[in] in CeedVector containing input state or @ref CEED_VECTOR_NONE if 1483 there are no active inputs 1484 @param[out] out CeedVector to store result of applying operator (must be 1485 distinct from @a in) or @ref CEED_VECTOR_NONE if there are no 1486 active outputs 1487 @param request Address of CeedRequest for non-blocking completion, else 1488 @ref CEED_REQUEST_IMMEDIATE 1489 1490 @return An error code: 0 - success, otherwise - failure 1491 1492 @ref User 1493 **/ 1494 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, 1495 CeedRequest *request) { 1496 int ierr; 1497 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1498 1499 if (op->num_elem) { 1500 // Standard Operator 1501 if (op->Apply) { 1502 ierr = op->Apply(op, in, out, request); CeedChk(ierr); 1503 } else { 1504 // Zero all output vectors 1505 CeedQFunction qf = op->qf; 1506 for (CeedInt i=0; i<qf->num_output_fields; i++) { 1507 CeedVector vec = op->output_fields[i]->vec; 1508 if (vec == CEED_VECTOR_ACTIVE) 1509 vec = out; 1510 if (vec != CEED_VECTOR_NONE) { 1511 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 1512 } 1513 } 1514 // Apply 1515 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 1516 } 1517 } else if (op->is_composite) { 1518 // Composite Operator 1519 if (op->ApplyComposite) { 1520 ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr); 1521 } else { 1522 CeedInt num_suboperators; 1523 ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1524 CeedOperator *sub_operators; 1525 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1526 1527 // Zero all output vectors 1528 if (out != CEED_VECTOR_NONE) { 1529 ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr); 1530 } 1531 for (CeedInt i=0; i<num_suboperators; i++) { 1532 for (CeedInt j=0; j<sub_operators[i]->qf->num_output_fields; j++) { 1533 CeedVector vec = sub_operators[i]->output_fields[j]->vec; 1534 if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) { 1535 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 1536 } 1537 } 1538 } 1539 // Apply 1540 for (CeedInt i=0; i<op->num_suboperators; i++) { 1541 ierr = CeedOperatorApplyAdd(op->sub_operators[i], in, out, request); 1542 CeedChk(ierr); 1543 } 1544 } 1545 } 1546 return CEED_ERROR_SUCCESS; 1547 } 1548 1549 /** 1550 @brief Apply CeedOperator to a vector and add result to output vector 1551 1552 This computes the action of the operator on the specified (active) input, 1553 yielding its (active) output. All inputs and outputs must be specified using 1554 CeedOperatorSetField(). 1555 1556 @param op CeedOperator to apply 1557 @param[in] in CeedVector containing input state or NULL if there are no 1558 active inputs 1559 @param[out] out CeedVector to sum in result of applying operator (must be 1560 distinct from @a in) or NULL if there are no active outputs 1561 @param request Address of CeedRequest for non-blocking completion, else 1562 @ref CEED_REQUEST_IMMEDIATE 1563 1564 @return An error code: 0 - success, otherwise - failure 1565 1566 @ref User 1567 **/ 1568 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, 1569 CeedRequest *request) { 1570 int ierr; 1571 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1572 1573 if (op->num_elem) { 1574 // Standard Operator 1575 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 1576 } else if (op->is_composite) { 1577 // Composite Operator 1578 if (op->ApplyAddComposite) { 1579 ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr); 1580 } else { 1581 CeedInt num_suboperators; 1582 ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1583 CeedOperator *sub_operators; 1584 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1585 1586 for (CeedInt i=0; i<num_suboperators; i++) { 1587 ierr = CeedOperatorApplyAdd(sub_operators[i], in, out, request); 1588 CeedChk(ierr); 1589 } 1590 } 1591 } 1592 return CEED_ERROR_SUCCESS; 1593 } 1594 1595 /** 1596 @brief Destroy a CeedOperator 1597 1598 @param op CeedOperator to destroy 1599 1600 @return An error code: 0 - success, otherwise - failure 1601 1602 @ref User 1603 **/ 1604 int CeedOperatorDestroy(CeedOperator *op) { 1605 int ierr; 1606 1607 if (!*op || --(*op)->ref_count > 0) return CEED_ERROR_SUCCESS; 1608 if ((*op)->Destroy) { 1609 ierr = (*op)->Destroy(*op); CeedChk(ierr); 1610 } 1611 ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr); 1612 // Free fields 1613 for (CeedInt i=0; i<(*op)->num_fields; i++) 1614 if ((*op)->input_fields[i]) { 1615 if ((*op)->input_fields[i]->elem_restr != CEED_ELEMRESTRICTION_NONE) { 1616 ierr = CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_restr); 1617 CeedChk(ierr); 1618 } 1619 if ((*op)->input_fields[i]->basis != CEED_BASIS_COLLOCATED) { 1620 ierr = CeedBasisDestroy(&(*op)->input_fields[i]->basis); CeedChk(ierr); 1621 } 1622 if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE && 1623 (*op)->input_fields[i]->vec != CEED_VECTOR_NONE ) { 1624 ierr = CeedVectorDestroy(&(*op)->input_fields[i]->vec); CeedChk(ierr); 1625 } 1626 ierr = CeedFree(&(*op)->input_fields[i]->field_name); CeedChk(ierr); 1627 ierr = CeedFree(&(*op)->input_fields[i]); CeedChk(ierr); 1628 } 1629 for (CeedInt i=0; i<(*op)->num_fields; i++) 1630 if ((*op)->output_fields[i]) { 1631 ierr = CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_restr); 1632 CeedChk(ierr); 1633 if ((*op)->output_fields[i]->basis != CEED_BASIS_COLLOCATED) { 1634 ierr = CeedBasisDestroy(&(*op)->output_fields[i]->basis); CeedChk(ierr); 1635 } 1636 if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE && 1637 (*op)->output_fields[i]->vec != CEED_VECTOR_NONE ) { 1638 ierr = CeedVectorDestroy(&(*op)->output_fields[i]->vec); CeedChk(ierr); 1639 } 1640 ierr = CeedFree(&(*op)->output_fields[i]->field_name); CeedChk(ierr); 1641 ierr = CeedFree(&(*op)->output_fields[i]); CeedChk(ierr); 1642 } 1643 // Destroy sub_operators 1644 for (CeedInt i=0; i<(*op)->num_suboperators; i++) 1645 if ((*op)->sub_operators[i]) { 1646 ierr = CeedOperatorDestroy(&(*op)->sub_operators[i]); CeedChk(ierr); 1647 } 1648 ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr); 1649 ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr); 1650 ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr); 1651 // Destroy any composite labels 1652 for (CeedInt i=0; i<(*op)->num_context_labels; i++) { 1653 ierr = CeedFree(&(*op)->context_labels[i]->sub_labels); CeedChk(ierr); 1654 ierr = CeedFree(&(*op)->context_labels[i]); CeedChk(ierr); 1655 } 1656 ierr = CeedFree(&(*op)->context_labels); CeedChk(ierr); 1657 1658 // Destroy fallback 1659 if ((*op)->op_fallback) { 1660 ierr = (*op)->qf_fallback->Destroy((*op)->qf_fallback); CeedChk(ierr); 1661 ierr = CeedFree(&(*op)->qf_fallback); CeedChk(ierr); 1662 ierr = (*op)->op_fallback->Destroy((*op)->op_fallback); CeedChk(ierr); 1663 ierr = CeedFree(&(*op)->op_fallback); CeedChk(ierr); 1664 } 1665 1666 // Destroy QF assembly cache 1667 ierr = CeedQFunctionAssemblyDataDestroy(&(*op)->qf_assembled); CeedChk(ierr); 1668 1669 ierr = CeedFree(&(*op)->input_fields); CeedChk(ierr); 1670 ierr = CeedFree(&(*op)->output_fields); CeedChk(ierr); 1671 ierr = CeedFree(&(*op)->sub_operators); CeedChk(ierr); 1672 ierr = CeedFree(op); CeedChk(ierr); 1673 return CEED_ERROR_SUCCESS; 1674 } 1675 1676 /// @} 1677