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