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, CeedInt *num_input_fields, 590 CeedOperatorField **input_fields, 591 CeedInt *num_output_fields, 592 CeedOperatorField **output_fields) { 593 if (op->composite) 594 // LCOV_EXCL_START 595 return CeedError(op->ceed, CEED_ERROR_MINOR, 596 "Not defined for composite operator"); 597 // LCOV_EXCL_STOP 598 599 if (num_input_fields) *num_input_fields = op->qf->num_input_fields; 600 if (input_fields) *input_fields = op->input_fields; 601 if (num_output_fields) *num_output_fields = op->qf->num_output_fields; 602 if (output_fields) *output_fields = op->output_fields; 603 return CEED_ERROR_SUCCESS; 604 } 605 606 /** 607 @brief Get the CeedElemRestriction of a CeedOperatorField 608 609 @param op_field CeedOperatorField 610 @param[out] rstr Variable to store CeedElemRestriction 611 612 @return An error code: 0 - success, otherwise - failure 613 614 @ref Backend 615 **/ 616 617 int CeedOperatorFieldGetElemRestriction(CeedOperatorField op_field, 618 CeedElemRestriction *rstr) { 619 *rstr = op_field->elem_restr; 620 return CEED_ERROR_SUCCESS; 621 } 622 623 /** 624 @brief Get the CeedBasis of a CeedOperatorField 625 626 @param op_field CeedOperatorField 627 @param[out] basis Variable to store CeedBasis 628 629 @return An error code: 0 - success, otherwise - failure 630 631 @ref Backend 632 **/ 633 634 int CeedOperatorFieldGetBasis(CeedOperatorField op_field, CeedBasis *basis) { 635 *basis = op_field->basis; 636 return CEED_ERROR_SUCCESS; 637 } 638 639 /** 640 @brief Get the CeedVector of a CeedOperatorField 641 642 @param op_field CeedOperatorField 643 @param[out] vec Variable to store CeedVector 644 645 @return An error code: 0 - success, otherwise - failure 646 647 @ref Backend 648 **/ 649 650 int CeedOperatorFieldGetVector(CeedOperatorField op_field, CeedVector *vec) { 651 *vec = op_field->vec; 652 return CEED_ERROR_SUCCESS; 653 } 654 655 /// @} 656 657 /// ---------------------------------------------------------------------------- 658 /// CeedOperator Public API 659 /// ---------------------------------------------------------------------------- 660 /// @addtogroup CeedOperatorUser 661 /// @{ 662 663 /** 664 @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and 665 CeedElemRestriction can be associated with CeedQFunction fields with 666 \ref CeedOperatorSetField. 667 668 @param ceed A Ceed object where the CeedOperator will be created 669 @param qf QFunction defining the action of the operator at quadrature points 670 @param dqf QFunction defining the action of the Jacobian of @a qf (or 671 @ref CEED_QFUNCTION_NONE) 672 @param dqfT QFunction defining the action of the transpose of the Jacobian 673 of @a qf (or @ref CEED_QFUNCTION_NONE) 674 @param[out] op Address of the variable where the newly created 675 CeedOperator will be stored 676 677 @return An error code: 0 - success, otherwise - failure 678 679 @ref User 680 */ 681 int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, 682 CeedQFunction dqfT, CeedOperator *op) { 683 int ierr; 684 685 if (!ceed->OperatorCreate) { 686 Ceed delegate; 687 ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr); 688 689 if (!delegate) 690 // LCOV_EXCL_START 691 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 692 "Backend does not support OperatorCreate"); 693 // LCOV_EXCL_STOP 694 695 ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr); 696 return CEED_ERROR_SUCCESS; 697 } 698 699 if (!qf || qf == CEED_QFUNCTION_NONE) 700 // LCOV_EXCL_START 701 return CeedError(ceed, CEED_ERROR_MINOR, 702 "Operator must have a valid QFunction."); 703 // LCOV_EXCL_STOP 704 ierr = CeedCalloc(1, op); CeedChk(ierr); 705 (*op)->ceed = ceed; 706 ierr = CeedReference(ceed); CeedChk(ierr); 707 (*op)->ref_count = 1; 708 (*op)->qf = qf; 709 ierr = CeedQFunctionReference(qf); CeedChk(ierr); 710 if (dqf && dqf != CEED_QFUNCTION_NONE) { 711 (*op)->dqf = dqf; 712 ierr = CeedQFunctionReference(dqf); CeedChk(ierr); 713 } 714 if (dqfT && dqfT != CEED_QFUNCTION_NONE) { 715 (*op)->dqfT = dqfT; 716 ierr = CeedQFunctionReference(dqfT); CeedChk(ierr); 717 } 718 ierr = CeedCalloc(16, &(*op)->input_fields); CeedChk(ierr); 719 ierr = CeedCalloc(16, &(*op)->output_fields); CeedChk(ierr); 720 ierr = ceed->OperatorCreate(*op); CeedChk(ierr); 721 return CEED_ERROR_SUCCESS; 722 } 723 724 /** 725 @brief Create an operator that composes the action of several operators 726 727 @param ceed A Ceed object where the CeedOperator will be created 728 @param[out] op Address of the variable where the newly created 729 Composite CeedOperator will be stored 730 731 @return An error code: 0 - success, otherwise - failure 732 733 @ref User 734 */ 735 int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) { 736 int ierr; 737 738 if (!ceed->CompositeOperatorCreate) { 739 Ceed delegate; 740 ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr); 741 742 if (delegate) { 743 ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr); 744 return CEED_ERROR_SUCCESS; 745 } 746 } 747 748 ierr = CeedCalloc(1, op); CeedChk(ierr); 749 (*op)->ceed = ceed; 750 ierr = CeedReference(ceed); CeedChk(ierr); 751 (*op)->composite = true; 752 ierr = CeedCalloc(16, &(*op)->sub_operators); CeedChk(ierr); 753 754 if (ceed->CompositeOperatorCreate) { 755 ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr); 756 } 757 return CEED_ERROR_SUCCESS; 758 } 759 760 /** 761 @brief Copy the pointer to a CeedOperator. Both pointers should 762 be destroyed with `CeedOperatorDestroy()`; 763 Note: If `*op_copy` is non-NULL, then it is assumed that 764 `*op_copy` is a pointer to a CeedOperator. This 765 CeedOperator will be destroyed if `*op_copy` is the only 766 reference to this CeedOperator. 767 768 @param op CeedOperator to copy reference to 769 @param[out] op_copy Variable to store copied reference 770 771 @return An error code: 0 - success, otherwise - failure 772 773 @ref User 774 **/ 775 int CeedOperatorReferenceCopy(CeedOperator op, CeedOperator *op_copy) { 776 int ierr; 777 778 ierr = CeedOperatorReference(op); CeedChk(ierr); 779 ierr = CeedOperatorDestroy(op_copy); CeedChk(ierr); 780 *op_copy = op; 781 return CEED_ERROR_SUCCESS; 782 } 783 784 /** 785 @brief Provide a field to a CeedOperator for use by its CeedQFunction 786 787 This function is used to specify both active and passive fields to a 788 CeedOperator. For passive fields, a vector @arg v must be provided. Passive 789 fields can inputs or outputs (updated in-place when operator is applied). 790 791 Active fields must be specified using this function, but their data (in a 792 CeedVector) is passed in CeedOperatorApply(). There can be at most one active 793 input and at most one active output. 794 795 @param op CeedOperator on which to provide the field 796 @param field_name Name of the field (to be matched with the name used by 797 CeedQFunction) 798 @param r CeedElemRestriction 799 @param b CeedBasis in which the field resides or @ref CEED_BASIS_COLLOCATED 800 if collocated with quadrature points 801 @param v CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE 802 if field is active or @ref CEED_VECTOR_NONE if using 803 @ref CEED_EVAL_WEIGHT in the QFunction 804 805 @return An error code: 0 - success, otherwise - failure 806 807 @ref User 808 **/ 809 int CeedOperatorSetField(CeedOperator op, const char *field_name, 810 CeedElemRestriction r, CeedBasis b, CeedVector v) { 811 int ierr; 812 if (op->composite) 813 // LCOV_EXCL_START 814 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 815 "Cannot add field to composite operator."); 816 // LCOV_EXCL_STOP 817 if (!r) 818 // LCOV_EXCL_START 819 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 820 "ElemRestriction r for field \"%s\" must be non-NULL.", 821 field_name); 822 // LCOV_EXCL_STOP 823 if (!b) 824 // LCOV_EXCL_START 825 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 826 "Basis b for field \"%s\" must be non-NULL.", 827 field_name); 828 // LCOV_EXCL_STOP 829 if (!v) 830 // LCOV_EXCL_START 831 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 832 "Vector v for field \"%s\" must be non-NULL.", 833 field_name); 834 // LCOV_EXCL_STOP 835 836 CeedInt num_elem; 837 ierr = CeedElemRestrictionGetNumElements(r, &num_elem); CeedChk(ierr); 838 if (r != CEED_ELEMRESTRICTION_NONE && op->has_restriction && 839 op->num_elem != num_elem) 840 // LCOV_EXCL_START 841 return CeedError(op->ceed, CEED_ERROR_DIMENSION, 842 "ElemRestriction with %d elements incompatible with prior " 843 "%d elements", num_elem, op->num_elem); 844 // LCOV_EXCL_STOP 845 846 CeedInt num_qpts = 0; 847 if (b != CEED_BASIS_COLLOCATED) { 848 ierr = CeedBasisGetNumQuadraturePoints(b, &num_qpts); CeedChk(ierr); 849 if (op->num_qpts && op->num_qpts != num_qpts) 850 // LCOV_EXCL_START 851 return CeedError(op->ceed, CEED_ERROR_DIMENSION, 852 "Basis with %d quadrature points " 853 "incompatible with prior %d points", num_qpts, 854 op->num_qpts); 855 // LCOV_EXCL_STOP 856 } 857 CeedQFunctionField qf_field; 858 CeedOperatorField *op_field; 859 for (CeedInt i=0; i<op->qf->num_input_fields; i++) { 860 if (!strcmp(field_name, (*op->qf->input_fields[i]).field_name)) { 861 qf_field = op->qf->input_fields[i]; 862 op_field = &op->input_fields[i]; 863 goto found; 864 } 865 } 866 for (CeedInt i=0; i<op->qf->num_output_fields; i++) { 867 if (!strcmp(field_name, (*op->qf->output_fields[i]).field_name)) { 868 qf_field = op->qf->output_fields[i]; 869 op_field = &op->output_fields[i]; 870 goto found; 871 } 872 } 873 // LCOV_EXCL_START 874 return CeedError(op->ceed, CEED_ERROR_INCOMPLETE, 875 "QFunction has no knowledge of field '%s'", 876 field_name); 877 // LCOV_EXCL_STOP 878 found: 879 ierr = CeedOperatorCheckField(op->ceed, qf_field, r, b); CeedChk(ierr); 880 ierr = CeedCalloc(1, op_field); CeedChk(ierr); 881 882 (*op_field)->vec = v; 883 if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) { 884 ierr = CeedVectorReference(v); CeedChk(ierr); 885 } 886 887 (*op_field)->elem_restr = r; 888 ierr = CeedElemRestrictionReference(r); CeedChk(ierr); 889 if (r != CEED_ELEMRESTRICTION_NONE) { 890 op->num_elem = num_elem; 891 op->has_restriction = true; // Restriction set, but num_elem may be 0 892 } 893 894 (*op_field)->basis = b; 895 if (b != CEED_BASIS_COLLOCATED) { 896 if (!op->num_qpts) { 897 ierr = CeedOperatorSetNumQuadraturePoints(op, num_qpts); CeedChk(ierr); 898 } 899 ierr = CeedBasisReference(b); CeedChk(ierr); 900 } 901 902 op->num_fields += 1; 903 size_t len = strlen(field_name); 904 char *tmp; 905 ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr); 906 memcpy(tmp, field_name, len+1); 907 (*op_field)->field_name = tmp; 908 return CEED_ERROR_SUCCESS; 909 } 910 911 /** 912 @brief Add a sub-operator to a composite CeedOperator 913 914 @param[out] composite_op Composite CeedOperator 915 @param sub_op Sub-operator CeedOperator 916 917 @return An error code: 0 - success, otherwise - failure 918 919 @ref User 920 */ 921 int CeedCompositeOperatorAddSub(CeedOperator composite_op, 922 CeedOperator sub_op) { 923 int ierr; 924 925 if (!composite_op->composite) 926 // LCOV_EXCL_START 927 return CeedError(composite_op->ceed, CEED_ERROR_MINOR, 928 "CeedOperator is not a composite operator"); 929 // LCOV_EXCL_STOP 930 931 if (composite_op->num_suboperators == CEED_COMPOSITE_MAX) 932 // LCOV_EXCL_START 933 return CeedError(composite_op->ceed, CEED_ERROR_UNSUPPORTED, 934 "Cannot add additional sub_operators"); 935 // LCOV_EXCL_STOP 936 937 composite_op->sub_operators[composite_op->num_suboperators] = sub_op; 938 ierr = CeedOperatorReference(sub_op); CeedChk(ierr); 939 composite_op->num_suboperators++; 940 return CEED_ERROR_SUCCESS; 941 } 942 943 /** 944 @brief Set the number of quadrature points associated with a CeedOperator. 945 This should be used when creating a CeedOperator where every 946 field has a collocated basis. This function cannot be used for 947 composite CeedOperators. 948 949 @param op CeedOperator 950 @param num_qpts Number of quadrature points to set 951 952 @return An error code: 0 - success, otherwise - failure 953 954 @ref Backend 955 **/ 956 957 int CeedOperatorSetNumQuadraturePoints(CeedOperator op, CeedInt num_qpts) { 958 if (op->composite) 959 // LCOV_EXCL_START 960 return CeedError(op->ceed, CEED_ERROR_MINOR, 961 "Not defined for composite operator"); 962 // LCOV_EXCL_STOP 963 if (op->num_qpts) 964 // LCOV_EXCL_START 965 return CeedError(op->ceed, CEED_ERROR_MINOR, 966 "Number of quadrature points already defined"); 967 // LCOV_EXCL_STOP 968 969 op->num_qpts = num_qpts; 970 return CEED_ERROR_SUCCESS; 971 } 972 973 /** 974 @brief View a CeedOperator 975 976 @param[in] op CeedOperator to view 977 @param[in] stream Stream to write; typically stdout/stderr or a file 978 979 @return Error code: 0 - success, otherwise - failure 980 981 @ref User 982 **/ 983 int CeedOperatorView(CeedOperator op, FILE *stream) { 984 int ierr; 985 986 if (op->composite) { 987 fprintf(stream, "Composite CeedOperator\n"); 988 989 for (CeedInt i=0; i<op->num_suboperators; i++) { 990 fprintf(stream, " SubOperator [%d]:\n", i); 991 ierr = CeedOperatorSingleView(op->sub_operators[i], 1, stream); 992 CeedChk(ierr); 993 } 994 } else { 995 fprintf(stream, "CeedOperator\n"); 996 ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr); 997 } 998 return CEED_ERROR_SUCCESS; 999 } 1000 1001 /** 1002 @brief Apply CeedOperator to a vector 1003 1004 This computes the action of the operator on the specified (active) input, 1005 yielding its (active) output. All inputs and outputs must be specified using 1006 CeedOperatorSetField(). 1007 1008 @param op CeedOperator to apply 1009 @param[in] in CeedVector containing input state or @ref CEED_VECTOR_NONE if 1010 there are no active inputs 1011 @param[out] out CeedVector to store result of applying operator (must be 1012 distinct from @a in) or @ref CEED_VECTOR_NONE if there are no 1013 active outputs 1014 @param request Address of CeedRequest for non-blocking completion, else 1015 @ref CEED_REQUEST_IMMEDIATE 1016 1017 @return An error code: 0 - success, otherwise - failure 1018 1019 @ref User 1020 **/ 1021 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, 1022 CeedRequest *request) { 1023 int ierr; 1024 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1025 1026 if (op->num_elem) { 1027 // Standard Operator 1028 if (op->Apply) { 1029 ierr = op->Apply(op, in, out, request); CeedChk(ierr); 1030 } else { 1031 // Zero all output vectors 1032 CeedQFunction qf = op->qf; 1033 for (CeedInt i=0; i<qf->num_output_fields; i++) { 1034 CeedVector vec = op->output_fields[i]->vec; 1035 if (vec == CEED_VECTOR_ACTIVE) 1036 vec = out; 1037 if (vec != CEED_VECTOR_NONE) { 1038 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 1039 } 1040 } 1041 // Apply 1042 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 1043 } 1044 } else if (op->composite) { 1045 // Composite Operator 1046 if (op->ApplyComposite) { 1047 ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr); 1048 } else { 1049 CeedInt num_suboperators; 1050 ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1051 CeedOperator *sub_operators; 1052 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1053 1054 // Zero all output vectors 1055 if (out != CEED_VECTOR_NONE) { 1056 ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr); 1057 } 1058 for (CeedInt i=0; i<num_suboperators; i++) { 1059 for (CeedInt j=0; j<sub_operators[i]->qf->num_output_fields; j++) { 1060 CeedVector vec = sub_operators[i]->output_fields[j]->vec; 1061 if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) { 1062 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 1063 } 1064 } 1065 } 1066 // Apply 1067 for (CeedInt i=0; i<op->num_suboperators; i++) { 1068 ierr = CeedOperatorApplyAdd(op->sub_operators[i], in, out, request); 1069 CeedChk(ierr); 1070 } 1071 } 1072 } 1073 return CEED_ERROR_SUCCESS; 1074 } 1075 1076 /** 1077 @brief Apply CeedOperator to a vector and add result to output vector 1078 1079 This computes the action of the operator on the specified (active) input, 1080 yielding its (active) output. All inputs and outputs must be specified using 1081 CeedOperatorSetField(). 1082 1083 @param op CeedOperator to apply 1084 @param[in] in CeedVector containing input state or NULL if there are no 1085 active inputs 1086 @param[out] out CeedVector to sum in result of applying operator (must be 1087 distinct from @a in) or NULL if there are no active outputs 1088 @param request Address of CeedRequest for non-blocking completion, else 1089 @ref CEED_REQUEST_IMMEDIATE 1090 1091 @return An error code: 0 - success, otherwise - failure 1092 1093 @ref User 1094 **/ 1095 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, 1096 CeedRequest *request) { 1097 int ierr; 1098 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1099 1100 if (op->num_elem) { 1101 // Standard Operator 1102 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 1103 } else if (op->composite) { 1104 // Composite Operator 1105 if (op->ApplyAddComposite) { 1106 ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr); 1107 } else { 1108 CeedInt num_suboperators; 1109 ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1110 CeedOperator *sub_operators; 1111 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1112 1113 for (CeedInt i=0; i<num_suboperators; i++) { 1114 ierr = CeedOperatorApplyAdd(sub_operators[i], in, out, request); 1115 CeedChk(ierr); 1116 } 1117 } 1118 } 1119 return CEED_ERROR_SUCCESS; 1120 } 1121 1122 /** 1123 @brief Destroy a CeedOperator 1124 1125 @param op CeedOperator to destroy 1126 1127 @return An error code: 0 - success, otherwise - failure 1128 1129 @ref User 1130 **/ 1131 int CeedOperatorDestroy(CeedOperator *op) { 1132 int ierr; 1133 1134 if (!*op || --(*op)->ref_count > 0) return CEED_ERROR_SUCCESS; 1135 if ((*op)->Destroy) { 1136 ierr = (*op)->Destroy(*op); CeedChk(ierr); 1137 } 1138 ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr); 1139 // Free fields 1140 for (int i=0; i<(*op)->num_fields; i++) 1141 if ((*op)->input_fields[i]) { 1142 if ((*op)->input_fields[i]->elem_restr != CEED_ELEMRESTRICTION_NONE) { 1143 ierr = CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_restr); 1144 CeedChk(ierr); 1145 } 1146 if ((*op)->input_fields[i]->basis != CEED_BASIS_COLLOCATED) { 1147 ierr = CeedBasisDestroy(&(*op)->input_fields[i]->basis); CeedChk(ierr); 1148 } 1149 if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE && 1150 (*op)->input_fields[i]->vec != CEED_VECTOR_NONE ) { 1151 ierr = CeedVectorDestroy(&(*op)->input_fields[i]->vec); CeedChk(ierr); 1152 } 1153 ierr = CeedFree(&(*op)->input_fields[i]->field_name); CeedChk(ierr); 1154 ierr = CeedFree(&(*op)->input_fields[i]); CeedChk(ierr); 1155 } 1156 for (int i=0; i<(*op)->num_fields; i++) 1157 if ((*op)->output_fields[i]) { 1158 ierr = CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_restr); 1159 CeedChk(ierr); 1160 if ((*op)->output_fields[i]->basis != CEED_BASIS_COLLOCATED) { 1161 ierr = CeedBasisDestroy(&(*op)->output_fields[i]->basis); CeedChk(ierr); 1162 } 1163 if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE && 1164 (*op)->output_fields[i]->vec != CEED_VECTOR_NONE ) { 1165 ierr = CeedVectorDestroy(&(*op)->output_fields[i]->vec); CeedChk(ierr); 1166 } 1167 ierr = CeedFree(&(*op)->output_fields[i]->field_name); CeedChk(ierr); 1168 ierr = CeedFree(&(*op)->output_fields[i]); CeedChk(ierr); 1169 } 1170 // Destroy sub_operators 1171 for (int i=0; i<(*op)->num_suboperators; i++) 1172 if ((*op)->sub_operators[i]) { 1173 ierr = CeedOperatorDestroy(&(*op)->sub_operators[i]); CeedChk(ierr); 1174 } 1175 if ((*op)->qf) 1176 // LCOV_EXCL_START 1177 (*op)->qf->operators_set--; 1178 // LCOV_EXCL_STOP 1179 ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr); 1180 if ((*op)->dqf && (*op)->dqf != CEED_QFUNCTION_NONE) 1181 // LCOV_EXCL_START 1182 (*op)->dqf->operators_set--; 1183 // LCOV_EXCL_STOP 1184 ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr); 1185 if ((*op)->dqfT && (*op)->dqfT != CEED_QFUNCTION_NONE) 1186 // LCOV_EXCL_START 1187 (*op)->dqfT->operators_set--; 1188 // LCOV_EXCL_STOP 1189 ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr); 1190 1191 // Destroy fallback 1192 if ((*op)->op_fallback) { 1193 ierr = (*op)->qf_fallback->Destroy((*op)->qf_fallback); CeedChk(ierr); 1194 ierr = CeedFree(&(*op)->qf_fallback); CeedChk(ierr); 1195 ierr = (*op)->op_fallback->Destroy((*op)->op_fallback); CeedChk(ierr); 1196 ierr = CeedFree(&(*op)->op_fallback); CeedChk(ierr); 1197 } 1198 1199 ierr = CeedFree(&(*op)->input_fields); CeedChk(ierr); 1200 ierr = CeedFree(&(*op)->output_fields); CeedChk(ierr); 1201 ierr = CeedFree(&(*op)->sub_operators); CeedChk(ierr); 1202 ierr = CeedFree(op); CeedChk(ierr); 1203 return CEED_ERROR_SUCCESS; 1204 } 1205 1206 /// @} 1207