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