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