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 <math.h> 21 #include <stdbool.h> 22 #include <stdio.h> 23 #include <string.h> 24 25 /// @file 26 /// Implementation of CeedOperator interfaces 27 28 /// ---------------------------------------------------------------------------- 29 /// CeedOperator Library Internal Functions 30 /// ---------------------------------------------------------------------------- 31 /// @addtogroup CeedOperatorDeveloper 32 /// @{ 33 34 /** 35 @brief Check if a CeedOperator Field matches the QFunction Field 36 37 @param[in] ceed Ceed object for error handling 38 @param[in] qf_field QFunction Field matching Operator Field 39 @param[in] r Operator Field ElemRestriction 40 @param[in] b Operator Field Basis 41 42 @return An error code: 0 - success, otherwise - failure 43 44 @ref Developer 45 **/ 46 static int CeedOperatorCheckField(Ceed ceed, CeedQFunctionField qf_field, 47 CeedElemRestriction r, CeedBasis b) { 48 int ierr; 49 CeedEvalMode eval_mode = qf_field->eval_mode; 50 CeedInt dim = 1, num_comp = 1, restr_num_comp = 1, size = qf_field->size; 51 // Restriction 52 if (r != CEED_ELEMRESTRICTION_NONE) { 53 if (eval_mode == CEED_EVAL_WEIGHT) { 54 // LCOV_EXCL_START 55 return CeedError(ceed, CEED_ERROR_INCOMPATIBLE, 56 "CEED_ELEMRESTRICTION_NONE should be used " 57 "for a field with eval mode CEED_EVAL_WEIGHT"); 58 // LCOV_EXCL_STOP 59 } 60 ierr = CeedElemRestrictionGetNumComponents(r, &restr_num_comp); 61 CeedChk(ierr); 62 } 63 if ((r == CEED_ELEMRESTRICTION_NONE) != (eval_mode == CEED_EVAL_WEIGHT)) { 64 // LCOV_EXCL_START 65 return CeedError(ceed, CEED_ERROR_INCOMPATIBLE, 66 "CEED_ELEMRESTRICTION_NONE and CEED_EVAL_WEIGHT " 67 "must be used together."); 68 // LCOV_EXCL_STOP 69 } 70 // Basis 71 if (b != CEED_BASIS_COLLOCATED) { 72 if (eval_mode == CEED_EVAL_NONE) 73 // LCOV_EXCL_START 74 return CeedError(ceed, CEED_ERROR_INCOMPATIBLE, 75 "Field '%s' configured with CEED_EVAL_NONE must " 76 "be used with CEED_BASIS_COLLOCATED", 77 // LCOV_EXCL_STOP 78 qf_field->field_name); 79 ierr = CeedBasisGetDimension(b, &dim); CeedChk(ierr); 80 ierr = CeedBasisGetNumComponents(b, &num_comp); CeedChk(ierr); 81 if (r != CEED_ELEMRESTRICTION_NONE && restr_num_comp != num_comp) { 82 // LCOV_EXCL_START 83 return CeedError(ceed, CEED_ERROR_DIMENSION, 84 "Field '%s' of size %d and EvalMode %s: ElemRestriction " 85 "has %d components, but Basis has %d components", 86 qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], 87 restr_num_comp, 88 num_comp); 89 // LCOV_EXCL_STOP 90 } 91 } 92 // Field size 93 switch(eval_mode) { 94 case CEED_EVAL_NONE: 95 if (size != restr_num_comp) 96 // LCOV_EXCL_START 97 return CeedError(ceed, CEED_ERROR_DIMENSION, 98 "Field '%s' of size %d and EvalMode %s: ElemRestriction has %d components", 99 qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], 100 restr_num_comp); 101 // LCOV_EXCL_STOP 102 break; 103 case CEED_EVAL_INTERP: 104 if (size != num_comp) 105 // LCOV_EXCL_START 106 return CeedError(ceed, CEED_ERROR_DIMENSION, 107 "Field '%s' of size %d and EvalMode %s: ElemRestriction/Basis has %d components", 108 qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], 109 num_comp); 110 // LCOV_EXCL_STOP 111 break; 112 case CEED_EVAL_GRAD: 113 if (size != num_comp * dim) 114 // LCOV_EXCL_START 115 return CeedError(ceed, CEED_ERROR_DIMENSION, 116 "Field '%s' of size %d and EvalMode %s in %d dimensions: " 117 "ElemRestriction/Basis has %d components", 118 qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], dim, 119 num_comp); 120 // LCOV_EXCL_STOP 121 break; 122 case CEED_EVAL_WEIGHT: 123 // No additional checks required 124 break; 125 case CEED_EVAL_DIV: 126 // Not implemented 127 break; 128 case CEED_EVAL_CURL: 129 // Not implemented 130 break; 131 } 132 return CEED_ERROR_SUCCESS; 133 } 134 135 /** 136 @brief Check if a CeedOperator is ready to be used. 137 138 @param[in] op CeedOperator to check 139 140 @return An error code: 0 - success, otherwise - failure 141 142 @ref Developer 143 **/ 144 int CeedOperatorCheckReady(CeedOperator op) { 145 int ierr; 146 Ceed ceed; 147 ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); 148 149 if (op->interface_setup) 150 return CEED_ERROR_SUCCESS; 151 152 CeedQFunction qf = op->qf; 153 if (op->composite) { 154 if (!op->num_suboperators) 155 // LCOV_EXCL_START 156 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No sub_operators set"); 157 // LCOV_EXCL_STOP 158 } else { 159 if (op->num_fields == 0) 160 // LCOV_EXCL_START 161 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No operator fields set"); 162 // LCOV_EXCL_STOP 163 if (op->num_fields < qf->num_input_fields + qf->num_output_fields) 164 // LCOV_EXCL_START 165 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set"); 166 // LCOV_EXCL_STOP 167 if (!op->has_restriction) 168 // LCOV_EXCL_START 169 return CeedError(ceed, CEED_ERROR_INCOMPLETE, 170 "At least one restriction required"); 171 // LCOV_EXCL_STOP 172 if (op->num_qpts == 0) 173 // LCOV_EXCL_START 174 return CeedError(ceed, CEED_ERROR_INCOMPLETE, 175 "At least one non-collocated basis is required " 176 "or the number of quadrature points must be set"); 177 // LCOV_EXCL_STOP 178 } 179 180 // Flag as immutable and ready 181 op->interface_setup = true; 182 if (op->qf && op->qf != CEED_QFUNCTION_NONE) 183 // LCOV_EXCL_START 184 op->qf->operators_set++; 185 // LCOV_EXCL_STOP 186 if (op->dqf && op->dqf != CEED_QFUNCTION_NONE) 187 // LCOV_EXCL_START 188 op->dqf->operators_set++; 189 // LCOV_EXCL_STOP 190 if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE) 191 // LCOV_EXCL_START 192 op->dqfT->operators_set++; 193 // LCOV_EXCL_STOP 194 return CEED_ERROR_SUCCESS; 195 } 196 197 /** 198 @brief View a field of a CeedOperator 199 200 @param[in] field Operator field to view 201 @param[in] qf_field QFunction field (carries field name) 202 @param[in] field_number Number of field being viewed 203 @param[in] sub true indicates sub-operator, which increases indentation; false for top-level operator 204 @param[in] input true for an input field; false for output field 205 @param[in] stream Stream to view to, e.g., stdout 206 207 @return An error code: 0 - success, otherwise - failure 208 209 @ref Utility 210 **/ 211 static int CeedOperatorFieldView(CeedOperatorField field, 212 CeedQFunctionField qf_field, 213 CeedInt field_number, bool sub, bool input, 214 FILE *stream) { 215 const char *pre = sub ? " " : ""; 216 const char *in_out = input ? "Input" : "Output"; 217 218 fprintf(stream, "%s %s Field [%d]:\n" 219 "%s Name: \"%s\"\n", 220 pre, in_out, field_number, pre, qf_field->field_name); 221 222 if (field->basis == CEED_BASIS_COLLOCATED) 223 fprintf(stream, "%s Collocated basis\n", pre); 224 225 if (field->vec == CEED_VECTOR_ACTIVE) 226 fprintf(stream, "%s Active vector\n", pre); 227 else if (field->vec == CEED_VECTOR_NONE) 228 fprintf(stream, "%s No vector\n", pre); 229 return CEED_ERROR_SUCCESS; 230 } 231 232 /** 233 @brief View a single CeedOperator 234 235 @param[in] op CeedOperator to view 236 @param[in] sub Boolean flag for sub-operator 237 @param[in] stream Stream to write; typically stdout/stderr or a file 238 239 @return Error code: 0 - success, otherwise - failure 240 241 @ref Utility 242 **/ 243 int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) { 244 int ierr; 245 const char *pre = sub ? " " : ""; 246 247 CeedInt total_fields = 0; 248 ierr = CeedOperatorGetNumArgs(op, &total_fields); CeedChk(ierr); 249 250 fprintf(stream, "%s %d Field%s\n", pre, total_fields, 251 total_fields>1 ? "s" : ""); 252 253 fprintf(stream, "%s %d Input Field%s:\n", pre, op->qf->num_input_fields, 254 op->qf->num_input_fields>1 ? "s" : ""); 255 for (CeedInt i=0; i<op->qf->num_input_fields; i++) { 256 ierr = CeedOperatorFieldView(op->input_fields[i], op->qf->input_fields[i], 257 i, sub, 1, stream); CeedChk(ierr); 258 } 259 260 fprintf(stream, "%s %d Output Field%s:\n", pre, op->qf->num_output_fields, 261 op->qf->num_output_fields>1 ? "s" : ""); 262 for (CeedInt i=0; i<op->qf->num_output_fields; i++) { 263 ierr = CeedOperatorFieldView(op->output_fields[i], op->qf->output_fields[i], 264 i, sub, 0, stream); CeedChk(ierr); 265 } 266 return CEED_ERROR_SUCCESS; 267 } 268 269 /** 270 @brief Find the active vector basis for a CeedOperator 271 272 @param[in] op CeedOperator to find active basis for 273 @param[out] active_basis Basis for active input vector 274 275 @return An error code: 0 - success, otherwise - failure 276 277 @ ref Developer 278 **/ 279 int CeedOperatorGetActiveBasis(CeedOperator op, CeedBasis *active_basis) { 280 *active_basis = NULL; 281 for (int i = 0; i < op->qf->num_input_fields; i++) 282 if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) { 283 *active_basis = op->input_fields[i]->basis; 284 break; 285 } 286 287 if (!*active_basis) { 288 // LCOV_EXCL_START 289 int ierr; 290 Ceed ceed; 291 ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); 292 return CeedError(ceed, CEED_ERROR_MINOR, 293 "No active CeedBasis found"); 294 // LCOV_EXCL_STOP 295 } 296 return CEED_ERROR_SUCCESS; 297 } 298 299 /** 300 @brief Find the active vector ElemRestriction for a CeedOperator 301 302 @param[in] op CeedOperator to find active basis for 303 @param[out] active_rstr ElemRestriction for active input vector 304 305 @return An error code: 0 - success, otherwise - failure 306 307 @ref Utility 308 **/ 309 int CeedOperatorGetActiveElemRestriction(CeedOperator op, 310 CeedElemRestriction *active_rstr) { 311 *active_rstr = NULL; 312 for (int i = 0; i < op->qf->num_input_fields; i++) 313 if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) { 314 *active_rstr = op->input_fields[i]->elem_restr; 315 break; 316 } 317 318 if (!*active_rstr) { 319 // LCOV_EXCL_START 320 int ierr; 321 Ceed ceed; 322 ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); 323 return CeedError(ceed, CEED_ERROR_INCOMPLETE, 324 "No active CeedElemRestriction found"); 325 // LCOV_EXCL_STOP 326 } 327 return CEED_ERROR_SUCCESS; 328 } 329 330 /// @} 331 332 /// ---------------------------------------------------------------------------- 333 /// CeedOperator Backend API 334 /// ---------------------------------------------------------------------------- 335 /// @addtogroup CeedOperatorBackend 336 /// @{ 337 338 /** 339 @brief Get the Ceed associated with a CeedOperator 340 341 @param op CeedOperator 342 @param[out] ceed Variable to store Ceed 343 344 @return An error code: 0 - success, otherwise - failure 345 346 @ref Backend 347 **/ 348 349 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) { 350 *ceed = op->ceed; 351 return CEED_ERROR_SUCCESS; 352 } 353 354 /** 355 @brief Get the number of elements associated with a CeedOperator 356 357 @param op CeedOperator 358 @param[out] num_elem Variable to store number of elements 359 360 @return An error code: 0 - success, otherwise - failure 361 362 @ref Backend 363 **/ 364 365 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) { 366 if (op->composite) 367 // LCOV_EXCL_START 368 return CeedError(op->ceed, CEED_ERROR_MINOR, 369 "Not defined for composite operator"); 370 // LCOV_EXCL_STOP 371 372 *num_elem = op->num_elem; 373 return CEED_ERROR_SUCCESS; 374 } 375 376 /** 377 @brief Get the number of quadrature points associated with a CeedOperator 378 379 @param op CeedOperator 380 @param[out] num_qpts Variable to store vector number of quadrature points 381 382 @return An error code: 0 - success, otherwise - failure 383 384 @ref Backend 385 **/ 386 387 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) { 388 if (op->composite) 389 // LCOV_EXCL_START 390 return CeedError(op->ceed, CEED_ERROR_MINOR, 391 "Not defined for composite operator"); 392 // LCOV_EXCL_STOP 393 394 *num_qpts = op->num_qpts; 395 return CEED_ERROR_SUCCESS; 396 } 397 398 /** 399 @brief Get the number of arguments associated with a CeedOperator 400 401 @param op CeedOperator 402 @param[out] num_args Variable to store vector number of arguments 403 404 @return An error code: 0 - success, otherwise - failure 405 406 @ref Backend 407 **/ 408 409 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *num_args) { 410 if (op->composite) 411 // LCOV_EXCL_START 412 return CeedError(op->ceed, CEED_ERROR_MINOR, 413 "Not defined for composite operators"); 414 // LCOV_EXCL_STOP 415 416 *num_args = op->num_fields; 417 return CEED_ERROR_SUCCESS; 418 } 419 420 /** 421 @brief Get the setup status of a CeedOperator 422 423 @param op CeedOperator 424 @param[out] is_setup_done Variable to store setup status 425 426 @return An error code: 0 - success, otherwise - failure 427 428 @ref Backend 429 **/ 430 431 int CeedOperatorIsSetupDone(CeedOperator op, bool *is_setup_done) { 432 *is_setup_done = op->backend_setup; 433 return CEED_ERROR_SUCCESS; 434 } 435 436 /** 437 @brief Get the QFunction associated with a CeedOperator 438 439 @param op CeedOperator 440 @param[out] qf Variable to store QFunction 441 442 @return An error code: 0 - success, otherwise - failure 443 444 @ref Backend 445 **/ 446 447 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) { 448 if (op->composite) 449 // LCOV_EXCL_START 450 return CeedError(op->ceed, CEED_ERROR_MINOR, 451 "Not defined for composite operator"); 452 // LCOV_EXCL_STOP 453 454 *qf = op->qf; 455 return CEED_ERROR_SUCCESS; 456 } 457 458 /** 459 @brief Get a boolean value indicating if the CeedOperator is composite 460 461 @param op CeedOperator 462 @param[out] is_composite Variable to store composite status 463 464 @return An error code: 0 - success, otherwise - failure 465 466 @ref Backend 467 **/ 468 469 int CeedOperatorIsComposite(CeedOperator op, bool *is_composite) { 470 *is_composite = op->composite; 471 return CEED_ERROR_SUCCESS; 472 } 473 474 /** 475 @brief Get the number of sub_operators associated with a CeedOperator 476 477 @param op CeedOperator 478 @param[out] num_suboperators Variable to store number of sub_operators 479 480 @return An error code: 0 - success, otherwise - failure 481 482 @ref Backend 483 **/ 484 485 int CeedOperatorGetNumSub(CeedOperator op, CeedInt *num_suboperators) { 486 if (!op->composite) 487 // LCOV_EXCL_START 488 return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator"); 489 // LCOV_EXCL_STOP 490 491 *num_suboperators = op->num_suboperators; 492 return CEED_ERROR_SUCCESS; 493 } 494 495 /** 496 @brief Get the list of sub_operators associated with a CeedOperator 497 498 @param op CeedOperator 499 @param[out] sub_operators Variable to store list of sub_operators 500 501 @return An error code: 0 - success, otherwise - failure 502 503 @ref Backend 504 **/ 505 506 int CeedOperatorGetSubList(CeedOperator op, CeedOperator **sub_operators) { 507 if (!op->composite) 508 // LCOV_EXCL_START 509 return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator"); 510 // LCOV_EXCL_STOP 511 512 *sub_operators = op->sub_operators; 513 return CEED_ERROR_SUCCESS; 514 } 515 516 /** 517 @brief Get the backend data of a CeedOperator 518 519 @param op CeedOperator 520 @param[out] data Variable to store data 521 522 @return An error code: 0 - success, otherwise - failure 523 524 @ref Backend 525 **/ 526 527 int CeedOperatorGetData(CeedOperator op, void *data) { 528 *(void **)data = op->data; 529 return CEED_ERROR_SUCCESS; 530 } 531 532 /** 533 @brief Set the backend data of a CeedOperator 534 535 @param[out] op CeedOperator 536 @param data Data to set 537 538 @return An error code: 0 - success, otherwise - failure 539 540 @ref Backend 541 **/ 542 543 int CeedOperatorSetData(CeedOperator op, void *data) { 544 op->data = data; 545 return CEED_ERROR_SUCCESS; 546 } 547 548 /** 549 @brief Increment the reference counter for a CeedOperator 550 551 @param op CeedOperator to increment the reference counter 552 553 @return An error code: 0 - success, otherwise - failure 554 555 @ref Backend 556 **/ 557 int CeedOperatorReference(CeedOperator op) { 558 op->ref_count++; 559 return CEED_ERROR_SUCCESS; 560 } 561 562 /** 563 @brief Set the setup flag of a CeedOperator to True 564 565 @param op CeedOperator 566 567 @return An error code: 0 - success, otherwise - failure 568 569 @ref Backend 570 **/ 571 572 int CeedOperatorSetSetupDone(CeedOperator op) { 573 op->backend_setup = true; 574 return CEED_ERROR_SUCCESS; 575 } 576 577 /** 578 @brief Get the CeedOperatorFields of a CeedOperator 579 580 @param op CeedOperator 581 @param[out] input_fields Variable to store input_fields 582 @param[out] output_fields Variable to store output_fields 583 584 @return An error code: 0 - success, otherwise - failure 585 586 @ref Backend 587 **/ 588 589 int CeedOperatorGetFields(CeedOperator op, CeedOperatorField **input_fields, 590 CeedOperatorField **output_fields) { 591 if (op->composite) 592 // LCOV_EXCL_START 593 return CeedError(op->ceed, CEED_ERROR_MINOR, 594 "Not defined for composite operator"); 595 // LCOV_EXCL_STOP 596 597 if (input_fields) *input_fields = op->input_fields; 598 if (output_fields) *output_fields = op->output_fields; 599 return CEED_ERROR_SUCCESS; 600 } 601 602 /** 603 @brief Get the CeedElemRestriction of a CeedOperatorField 604 605 @param op_field CeedOperatorField 606 @param[out] rstr Variable to store CeedElemRestriction 607 608 @return An error code: 0 - success, otherwise - failure 609 610 @ref Backend 611 **/ 612 613 int CeedOperatorFieldGetElemRestriction(CeedOperatorField op_field, 614 CeedElemRestriction *rstr) { 615 *rstr = op_field->elem_restr; 616 return CEED_ERROR_SUCCESS; 617 } 618 619 /** 620 @brief Get the CeedBasis of a CeedOperatorField 621 622 @param op_field CeedOperatorField 623 @param[out] basis Variable to store CeedBasis 624 625 @return An error code: 0 - success, otherwise - failure 626 627 @ref Backend 628 **/ 629 630 int CeedOperatorFieldGetBasis(CeedOperatorField op_field, CeedBasis *basis) { 631 *basis = op_field->basis; 632 return CEED_ERROR_SUCCESS; 633 } 634 635 /** 636 @brief Get the CeedVector of a CeedOperatorField 637 638 @param op_field CeedOperatorField 639 @param[out] vec Variable to store CeedVector 640 641 @return An error code: 0 - success, otherwise - failure 642 643 @ref Backend 644 **/ 645 646 int CeedOperatorFieldGetVector(CeedOperatorField op_field, CeedVector *vec) { 647 *vec = op_field->vec; 648 return CEED_ERROR_SUCCESS; 649 } 650 651 /// @} 652 653 /// ---------------------------------------------------------------------------- 654 /// CeedOperator Public API 655 /// ---------------------------------------------------------------------------- 656 /// @addtogroup CeedOperatorUser 657 /// @{ 658 659 /** 660 @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and 661 CeedElemRestriction can be associated with CeedQFunction fields with 662 \ref CeedOperatorSetField. 663 664 @param ceed A Ceed object where the CeedOperator will be created 665 @param qf QFunction defining the action of the operator at quadrature points 666 @param dqf QFunction defining the action of the Jacobian of @a qf (or 667 @ref CEED_QFUNCTION_NONE) 668 @param dqfT QFunction defining the action of the transpose of the Jacobian 669 of @a qf (or @ref CEED_QFUNCTION_NONE) 670 @param[out] op Address of the variable where the newly created 671 CeedOperator will be stored 672 673 @return An error code: 0 - success, otherwise - failure 674 675 @ref User 676 */ 677 int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, 678 CeedQFunction dqfT, CeedOperator *op) { 679 int ierr; 680 681 if (!ceed->OperatorCreate) { 682 Ceed delegate; 683 ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr); 684 685 if (!delegate) 686 // LCOV_EXCL_START 687 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 688 "Backend does not support OperatorCreate"); 689 // LCOV_EXCL_STOP 690 691 ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr); 692 return CEED_ERROR_SUCCESS; 693 } 694 695 if (!qf || qf == CEED_QFUNCTION_NONE) 696 // LCOV_EXCL_START 697 return CeedError(ceed, CEED_ERROR_MINOR, 698 "Operator must have a valid QFunction."); 699 // LCOV_EXCL_STOP 700 ierr = CeedCalloc(1, op); CeedChk(ierr); 701 (*op)->ceed = ceed; 702 ierr = CeedReference(ceed); CeedChk(ierr); 703 (*op)->ref_count = 1; 704 (*op)->qf = qf; 705 ierr = CeedQFunctionReference(qf); CeedChk(ierr); 706 if (dqf && dqf != CEED_QFUNCTION_NONE) { 707 (*op)->dqf = dqf; 708 ierr = CeedQFunctionReference(dqf); CeedChk(ierr); 709 } 710 if (dqfT && dqfT != CEED_QFUNCTION_NONE) { 711 (*op)->dqfT = dqfT; 712 ierr = CeedQFunctionReference(dqfT); CeedChk(ierr); 713 } 714 ierr = CeedCalloc(16, &(*op)->input_fields); CeedChk(ierr); 715 ierr = CeedCalloc(16, &(*op)->output_fields); CeedChk(ierr); 716 ierr = ceed->OperatorCreate(*op); CeedChk(ierr); 717 return CEED_ERROR_SUCCESS; 718 } 719 720 /** 721 @brief Create an operator that composes the action of several operators 722 723 @param ceed A Ceed object where the CeedOperator will be created 724 @param[out] op Address of the variable where the newly created 725 Composite CeedOperator will be stored 726 727 @return An error code: 0 - success, otherwise - failure 728 729 @ref User 730 */ 731 int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) { 732 int ierr; 733 734 if (!ceed->CompositeOperatorCreate) { 735 Ceed delegate; 736 ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr); 737 738 if (delegate) { 739 ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr); 740 return CEED_ERROR_SUCCESS; 741 } 742 } 743 744 ierr = CeedCalloc(1, op); CeedChk(ierr); 745 (*op)->ceed = ceed; 746 ierr = CeedReference(ceed); CeedChk(ierr); 747 (*op)->composite = true; 748 ierr = CeedCalloc(16, &(*op)->sub_operators); CeedChk(ierr); 749 750 if (ceed->CompositeOperatorCreate) { 751 ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr); 752 } 753 return CEED_ERROR_SUCCESS; 754 } 755 756 /** 757 @brief Copy the pointer to a CeedOperator. Both pointers should 758 be destroyed with `CeedOperatorDestroy()`; 759 Note: If `*op_copy` is non-NULL, then it is assumed that 760 `*op_copy` is a pointer to a CeedOperator. This 761 CeedOperator will be destroyed if `*op_copy` is the only 762 reference to this CeedOperator. 763 764 @param op CeedOperator to copy reference to 765 @param[out] op_copy Variable to store copied reference 766 767 @return An error code: 0 - success, otherwise - failure 768 769 @ref User 770 **/ 771 int CeedOperatorReferenceCopy(CeedOperator op, CeedOperator *op_copy) { 772 int ierr; 773 774 ierr = CeedOperatorReference(op); CeedChk(ierr); 775 ierr = CeedOperatorDestroy(op_copy); CeedChk(ierr); 776 *op_copy = op; 777 return CEED_ERROR_SUCCESS; 778 } 779 780 /** 781 @brief Provide a field to a CeedOperator for use by its CeedQFunction 782 783 This function is used to specify both active and passive fields to a 784 CeedOperator. For passive fields, a vector @arg v must be provided. Passive 785 fields can inputs or outputs (updated in-place when operator is applied). 786 787 Active fields must be specified using this function, but their data (in a 788 CeedVector) is passed in CeedOperatorApply(). There can be at most one active 789 input and at most one active output. 790 791 @param op CeedOperator on which to provide the field 792 @param field_name Name of the field (to be matched with the name used by 793 CeedQFunction) 794 @param r CeedElemRestriction 795 @param b CeedBasis in which the field resides or @ref CEED_BASIS_COLLOCATED 796 if collocated with quadrature points 797 @param v CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE 798 if field is active or @ref CEED_VECTOR_NONE if using 799 @ref CEED_EVAL_WEIGHT in the QFunction 800 801 @return An error code: 0 - success, otherwise - failure 802 803 @ref User 804 **/ 805 int CeedOperatorSetField(CeedOperator op, const char *field_name, 806 CeedElemRestriction r, CeedBasis b, CeedVector v) { 807 int ierr; 808 if (op->composite) 809 // LCOV_EXCL_START 810 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 811 "Cannot add field to composite operator."); 812 // LCOV_EXCL_STOP 813 if (!r) 814 // LCOV_EXCL_START 815 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 816 "ElemRestriction r for field \"%s\" must be non-NULL.", 817 field_name); 818 // LCOV_EXCL_STOP 819 if (!b) 820 // LCOV_EXCL_START 821 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 822 "Basis b for field \"%s\" must be non-NULL.", 823 field_name); 824 // LCOV_EXCL_STOP 825 if (!v) 826 // LCOV_EXCL_START 827 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 828 "Vector v for field \"%s\" must be non-NULL.", 829 field_name); 830 // LCOV_EXCL_STOP 831 832 CeedInt num_elem; 833 ierr = CeedElemRestrictionGetNumElements(r, &num_elem); CeedChk(ierr); 834 if (r != CEED_ELEMRESTRICTION_NONE && op->has_restriction && 835 op->num_elem != num_elem) 836 // LCOV_EXCL_START 837 return CeedError(op->ceed, CEED_ERROR_DIMENSION, 838 "ElemRestriction with %d elements incompatible with prior " 839 "%d elements", num_elem, op->num_elem); 840 // LCOV_EXCL_STOP 841 842 CeedInt num_qpts = 0; 843 if (b != CEED_BASIS_COLLOCATED) { 844 ierr = CeedBasisGetNumQuadraturePoints(b, &num_qpts); CeedChk(ierr); 845 if (op->num_qpts && op->num_qpts != num_qpts) 846 // LCOV_EXCL_START 847 return CeedError(op->ceed, CEED_ERROR_DIMENSION, 848 "Basis with %d quadrature points " 849 "incompatible with prior %d points", num_qpts, 850 op->num_qpts); 851 // LCOV_EXCL_STOP 852 } 853 CeedQFunctionField qf_field; 854 CeedOperatorField *op_field; 855 for (CeedInt i=0; i<op->qf->num_input_fields; i++) { 856 if (!strcmp(field_name, (*op->qf->input_fields[i]).field_name)) { 857 qf_field = op->qf->input_fields[i]; 858 op_field = &op->input_fields[i]; 859 goto found; 860 } 861 } 862 for (CeedInt i=0; i<op->qf->num_output_fields; i++) { 863 if (!strcmp(field_name, (*op->qf->output_fields[i]).field_name)) { 864 qf_field = op->qf->output_fields[i]; 865 op_field = &op->output_fields[i]; 866 goto found; 867 } 868 } 869 // LCOV_EXCL_START 870 return CeedError(op->ceed, CEED_ERROR_INCOMPLETE, 871 "QFunction has no knowledge of field '%s'", 872 field_name); 873 // LCOV_EXCL_STOP 874 found: 875 ierr = CeedOperatorCheckField(op->ceed, qf_field, r, b); CeedChk(ierr); 876 ierr = CeedCalloc(1, op_field); CeedChk(ierr); 877 878 (*op_field)->vec = v; 879 if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) { 880 ierr = CeedVectorReference(v); CeedChk(ierr); 881 } 882 883 (*op_field)->elem_restr = r; 884 ierr = CeedElemRestrictionReference(r); CeedChk(ierr); 885 if (r != CEED_ELEMRESTRICTION_NONE) { 886 op->num_elem = num_elem; 887 op->has_restriction = true; // Restriction set, but num_elem may be 0 888 } 889 890 (*op_field)->basis = b; 891 if (b != CEED_BASIS_COLLOCATED) { 892 if (!op->num_qpts) { 893 ierr = CeedOperatorSetNumQuadraturePoints(op, num_qpts); CeedChk(ierr); 894 } 895 ierr = CeedBasisReference(b); CeedChk(ierr); 896 } 897 898 op->num_fields += 1; 899 size_t len = strlen(field_name); 900 char *tmp; 901 ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr); 902 memcpy(tmp, field_name, len+1); 903 (*op_field)->field_name = tmp; 904 return CEED_ERROR_SUCCESS; 905 } 906 907 /** 908 @brief Add a sub-operator to a composite CeedOperator 909 910 @param[out] composite_op Composite CeedOperator 911 @param sub_op Sub-operator CeedOperator 912 913 @return An error code: 0 - success, otherwise - failure 914 915 @ref User 916 */ 917 int CeedCompositeOperatorAddSub(CeedOperator composite_op, 918 CeedOperator sub_op) { 919 int ierr; 920 921 if (!composite_op->composite) 922 // LCOV_EXCL_START 923 return CeedError(composite_op->ceed, CEED_ERROR_MINOR, 924 "CeedOperator is not a composite operator"); 925 // LCOV_EXCL_STOP 926 927 if (composite_op->num_suboperators == CEED_COMPOSITE_MAX) 928 // LCOV_EXCL_START 929 return CeedError(composite_op->ceed, CEED_ERROR_UNSUPPORTED, 930 "Cannot add additional sub_operators"); 931 // LCOV_EXCL_STOP 932 933 composite_op->sub_operators[composite_op->num_suboperators] = sub_op; 934 ierr = CeedOperatorReference(sub_op); CeedChk(ierr); 935 composite_op->num_suboperators++; 936 return CEED_ERROR_SUCCESS; 937 } 938 939 /** 940 @brief Set the number of quadrature points associated with a CeedOperator. 941 This should be used when creating a CeedOperator where every 942 field has a collocated basis. This function cannot be used for 943 composite CeedOperators. 944 945 @param op CeedOperator 946 @param num_qpts Number of quadrature points to set 947 948 @return An error code: 0 - success, otherwise - failure 949 950 @ref Backend 951 **/ 952 953 int CeedOperatorSetNumQuadraturePoints(CeedOperator op, CeedInt num_qpts) { 954 if (op->composite) 955 // LCOV_EXCL_START 956 return CeedError(op->ceed, CEED_ERROR_MINOR, 957 "Not defined for composite operator"); 958 // LCOV_EXCL_STOP 959 if (op->num_qpts) 960 // LCOV_EXCL_START 961 return CeedError(op->ceed, CEED_ERROR_MINOR, 962 "Number of quadrature points already defined"); 963 // LCOV_EXCL_STOP 964 965 op->num_qpts = num_qpts; 966 return CEED_ERROR_SUCCESS; 967 } 968 969 /** 970 @brief View a CeedOperator 971 972 @param[in] op CeedOperator to view 973 @param[in] stream Stream to write; typically stdout/stderr or a file 974 975 @return Error code: 0 - success, otherwise - failure 976 977 @ref User 978 **/ 979 int CeedOperatorView(CeedOperator op, FILE *stream) { 980 int ierr; 981 982 if (op->composite) { 983 fprintf(stream, "Composite CeedOperator\n"); 984 985 for (CeedInt i=0; i<op->num_suboperators; i++) { 986 fprintf(stream, " SubOperator [%d]:\n", i); 987 ierr = CeedOperatorSingleView(op->sub_operators[i], 1, stream); 988 CeedChk(ierr); 989 } 990 } else { 991 fprintf(stream, "CeedOperator\n"); 992 ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr); 993 } 994 return CEED_ERROR_SUCCESS; 995 } 996 997 /** 998 @brief Apply CeedOperator to a vector 999 1000 This computes the action of the operator on the specified (active) input, 1001 yielding its (active) output. All inputs and outputs must be specified using 1002 CeedOperatorSetField(). 1003 1004 @param op CeedOperator to apply 1005 @param[in] in CeedVector containing input state or @ref CEED_VECTOR_NONE if 1006 there are no active inputs 1007 @param[out] out CeedVector to store result of applying operator (must be 1008 distinct from @a in) or @ref CEED_VECTOR_NONE if there are no 1009 active outputs 1010 @param request Address of CeedRequest for non-blocking completion, else 1011 @ref CEED_REQUEST_IMMEDIATE 1012 1013 @return An error code: 0 - success, otherwise - failure 1014 1015 @ref User 1016 **/ 1017 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, 1018 CeedRequest *request) { 1019 int ierr; 1020 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1021 1022 if (op->num_elem) { 1023 // Standard Operator 1024 if (op->Apply) { 1025 ierr = op->Apply(op, in, out, request); CeedChk(ierr); 1026 } else { 1027 // Zero all output vectors 1028 CeedQFunction qf = op->qf; 1029 for (CeedInt i=0; i<qf->num_output_fields; i++) { 1030 CeedVector vec = op->output_fields[i]->vec; 1031 if (vec == CEED_VECTOR_ACTIVE) 1032 vec = out; 1033 if (vec != CEED_VECTOR_NONE) { 1034 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 1035 } 1036 } 1037 // Apply 1038 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 1039 } 1040 } else if (op->composite) { 1041 // Composite Operator 1042 if (op->ApplyComposite) { 1043 ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr); 1044 } else { 1045 CeedInt num_suboperators; 1046 ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1047 CeedOperator *sub_operators; 1048 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1049 1050 // Zero all output vectors 1051 if (out != CEED_VECTOR_NONE) { 1052 ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr); 1053 } 1054 for (CeedInt i=0; i<num_suboperators; i++) { 1055 for (CeedInt j=0; j<sub_operators[i]->qf->num_output_fields; j++) { 1056 CeedVector vec = sub_operators[i]->output_fields[j]->vec; 1057 if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) { 1058 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 1059 } 1060 } 1061 } 1062 // Apply 1063 for (CeedInt i=0; i<op->num_suboperators; i++) { 1064 ierr = CeedOperatorApplyAdd(op->sub_operators[i], in, out, request); 1065 CeedChk(ierr); 1066 } 1067 } 1068 } 1069 return CEED_ERROR_SUCCESS; 1070 } 1071 1072 /** 1073 @brief Apply CeedOperator to a vector and add result to output vector 1074 1075 This computes the action of the operator on the specified (active) input, 1076 yielding its (active) output. All inputs and outputs must be specified using 1077 CeedOperatorSetField(). 1078 1079 @param op CeedOperator to apply 1080 @param[in] in CeedVector containing input state or NULL if there are no 1081 active inputs 1082 @param[out] out CeedVector to sum in result of applying operator (must be 1083 distinct from @a in) or NULL if there are no active outputs 1084 @param request Address of CeedRequest for non-blocking completion, else 1085 @ref CEED_REQUEST_IMMEDIATE 1086 1087 @return An error code: 0 - success, otherwise - failure 1088 1089 @ref User 1090 **/ 1091 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, 1092 CeedRequest *request) { 1093 int ierr; 1094 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1095 1096 if (op->num_elem) { 1097 // Standard Operator 1098 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 1099 } else if (op->composite) { 1100 // Composite Operator 1101 if (op->ApplyAddComposite) { 1102 ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr); 1103 } else { 1104 CeedInt num_suboperators; 1105 ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1106 CeedOperator *sub_operators; 1107 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1108 1109 for (CeedInt i=0; i<num_suboperators; i++) { 1110 ierr = CeedOperatorApplyAdd(sub_operators[i], in, out, request); 1111 CeedChk(ierr); 1112 } 1113 } 1114 } 1115 return CEED_ERROR_SUCCESS; 1116 } 1117 1118 /** 1119 @brief Destroy a CeedOperator 1120 1121 @param op CeedOperator to destroy 1122 1123 @return An error code: 0 - success, otherwise - failure 1124 1125 @ref User 1126 **/ 1127 int CeedOperatorDestroy(CeedOperator *op) { 1128 int ierr; 1129 1130 if (!*op || --(*op)->ref_count > 0) return CEED_ERROR_SUCCESS; 1131 if ((*op)->Destroy) { 1132 ierr = (*op)->Destroy(*op); CeedChk(ierr); 1133 } 1134 ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr); 1135 // Free fields 1136 for (int i=0; i<(*op)->num_fields; i++) 1137 if ((*op)->input_fields[i]) { 1138 if ((*op)->input_fields[i]->elem_restr != CEED_ELEMRESTRICTION_NONE) { 1139 ierr = CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_restr); 1140 CeedChk(ierr); 1141 } 1142 if ((*op)->input_fields[i]->basis != CEED_BASIS_COLLOCATED) { 1143 ierr = CeedBasisDestroy(&(*op)->input_fields[i]->basis); CeedChk(ierr); 1144 } 1145 if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE && 1146 (*op)->input_fields[i]->vec != CEED_VECTOR_NONE ) { 1147 ierr = CeedVectorDestroy(&(*op)->input_fields[i]->vec); CeedChk(ierr); 1148 } 1149 ierr = CeedFree(&(*op)->input_fields[i]->field_name); CeedChk(ierr); 1150 ierr = CeedFree(&(*op)->input_fields[i]); CeedChk(ierr); 1151 } 1152 for (int i=0; i<(*op)->num_fields; i++) 1153 if ((*op)->output_fields[i]) { 1154 ierr = CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_restr); 1155 CeedChk(ierr); 1156 if ((*op)->output_fields[i]->basis != CEED_BASIS_COLLOCATED) { 1157 ierr = CeedBasisDestroy(&(*op)->output_fields[i]->basis); CeedChk(ierr); 1158 } 1159 if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE && 1160 (*op)->output_fields[i]->vec != CEED_VECTOR_NONE ) { 1161 ierr = CeedVectorDestroy(&(*op)->output_fields[i]->vec); CeedChk(ierr); 1162 } 1163 ierr = CeedFree(&(*op)->output_fields[i]->field_name); CeedChk(ierr); 1164 ierr = CeedFree(&(*op)->output_fields[i]); CeedChk(ierr); 1165 } 1166 // Destroy sub_operators 1167 for (int i=0; i<(*op)->num_suboperators; i++) 1168 if ((*op)->sub_operators[i]) { 1169 ierr = CeedOperatorDestroy(&(*op)->sub_operators[i]); CeedChk(ierr); 1170 } 1171 if ((*op)->qf) 1172 // LCOV_EXCL_START 1173 (*op)->qf->operators_set--; 1174 // LCOV_EXCL_STOP 1175 ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr); 1176 if ((*op)->dqf && (*op)->dqf != CEED_QFUNCTION_NONE) 1177 // LCOV_EXCL_START 1178 (*op)->dqf->operators_set--; 1179 // LCOV_EXCL_STOP 1180 ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr); 1181 if ((*op)->dqfT && (*op)->dqfT != CEED_QFUNCTION_NONE) 1182 // LCOV_EXCL_START 1183 (*op)->dqfT->operators_set--; 1184 // LCOV_EXCL_STOP 1185 ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr); 1186 1187 // Destroy fallback 1188 if ((*op)->op_fallback) { 1189 ierr = (*op)->qf_fallback->Destroy((*op)->qf_fallback); CeedChk(ierr); 1190 ierr = CeedFree(&(*op)->qf_fallback); CeedChk(ierr); 1191 ierr = (*op)->op_fallback->Destroy((*op)->op_fallback); CeedChk(ierr); 1192 ierr = CeedFree(&(*op)->op_fallback); CeedChk(ierr); 1193 } 1194 1195 ierr = CeedFree(&(*op)->input_fields); CeedChk(ierr); 1196 ierr = CeedFree(&(*op)->output_fields); CeedChk(ierr); 1197 ierr = CeedFree(&(*op)->sub_operators); CeedChk(ierr); 1198 ierr = CeedFree(op); CeedChk(ierr); 1199 return CEED_ERROR_SUCCESS; 1200 } 1201 1202 /// @} 1203