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