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->is_interface_setup) 150 return CEED_ERROR_SUCCESS; 151 152 CeedQFunction qf = op->qf; 153 if (op->is_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->is_interface_setup = true; 182 if (op->qf && op->qf != CEED_QFUNCTION_NONE) 183 // LCOV_EXCL_START 184 op->qf->is_immutable = true; 185 // LCOV_EXCL_STOP 186 if (op->dqf && op->dqf != CEED_QFUNCTION_NONE) 187 // LCOV_EXCL_START 188 op->dqf->is_immutable = true; 189 // LCOV_EXCL_STOP 190 if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE) 191 // LCOV_EXCL_START 192 op->dqfT->is_immutable = true; 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->is_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->is_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->is_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->is_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->is_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->is_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->is_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->is_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->is_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)->is_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->is_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 (op->is_immutable) 740 // LCOV_EXCL_START 741 return CeedError(op->ceed, CEED_ERROR_MAJOR, 742 "Operator cannot be changed after set as immutable"); 743 // LCOV_EXCL_STOP 744 if (!r) 745 // LCOV_EXCL_START 746 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 747 "ElemRestriction r for field \"%s\" must be non-NULL.", 748 field_name); 749 // LCOV_EXCL_STOP 750 if (!b) 751 // LCOV_EXCL_START 752 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 753 "Basis b for field \"%s\" must be non-NULL.", 754 field_name); 755 // LCOV_EXCL_STOP 756 if (!v) 757 // LCOV_EXCL_START 758 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 759 "Vector v for field \"%s\" must be non-NULL.", 760 field_name); 761 // LCOV_EXCL_STOP 762 763 CeedInt num_elem; 764 ierr = CeedElemRestrictionGetNumElements(r, &num_elem); CeedChk(ierr); 765 if (r != CEED_ELEMRESTRICTION_NONE && op->has_restriction && 766 op->num_elem != num_elem) 767 // LCOV_EXCL_START 768 return CeedError(op->ceed, CEED_ERROR_DIMENSION, 769 "ElemRestriction with %d elements incompatible with prior " 770 "%d elements", num_elem, op->num_elem); 771 // LCOV_EXCL_STOP 772 773 CeedInt num_qpts = 0; 774 if (b != CEED_BASIS_COLLOCATED) { 775 ierr = CeedBasisGetNumQuadraturePoints(b, &num_qpts); CeedChk(ierr); 776 if (op->num_qpts && op->num_qpts != num_qpts) 777 // LCOV_EXCL_START 778 return CeedError(op->ceed, CEED_ERROR_DIMENSION, 779 "Basis with %d quadrature points " 780 "incompatible with prior %d points", num_qpts, 781 op->num_qpts); 782 // LCOV_EXCL_STOP 783 } 784 CeedQFunctionField qf_field; 785 CeedOperatorField *op_field; 786 for (CeedInt i=0; i<op->qf->num_input_fields; i++) { 787 if (!strcmp(field_name, (*op->qf->input_fields[i]).field_name)) { 788 qf_field = op->qf->input_fields[i]; 789 op_field = &op->input_fields[i]; 790 goto found; 791 } 792 } 793 for (CeedInt i=0; i<op->qf->num_output_fields; i++) { 794 if (!strcmp(field_name, (*op->qf->output_fields[i]).field_name)) { 795 qf_field = op->qf->output_fields[i]; 796 op_field = &op->output_fields[i]; 797 goto found; 798 } 799 } 800 // LCOV_EXCL_START 801 return CeedError(op->ceed, CEED_ERROR_INCOMPLETE, 802 "QFunction has no knowledge of field '%s'", 803 field_name); 804 // LCOV_EXCL_STOP 805 found: 806 ierr = CeedOperatorCheckField(op->ceed, qf_field, r, b); CeedChk(ierr); 807 ierr = CeedCalloc(1, op_field); CeedChk(ierr); 808 809 (*op_field)->vec = v; 810 if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) { 811 ierr = CeedVectorReference(v); CeedChk(ierr); 812 } 813 814 (*op_field)->elem_restr = r; 815 ierr = CeedElemRestrictionReference(r); CeedChk(ierr); 816 if (r != CEED_ELEMRESTRICTION_NONE) { 817 op->num_elem = num_elem; 818 op->has_restriction = true; // Restriction set, but num_elem may be 0 819 } 820 821 (*op_field)->basis = b; 822 if (b != CEED_BASIS_COLLOCATED) { 823 if (!op->num_qpts) { 824 ierr = CeedOperatorSetNumQuadraturePoints(op, num_qpts); CeedChk(ierr); 825 } 826 ierr = CeedBasisReference(b); CeedChk(ierr); 827 } 828 829 op->num_fields += 1; 830 size_t len = strlen(field_name); 831 char *tmp; 832 ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr); 833 memcpy(tmp, field_name, len+1); 834 (*op_field)->field_name = tmp; 835 return CEED_ERROR_SUCCESS; 836 } 837 838 /** 839 @brief Get the CeedOperatorFields of a CeedOperator 840 841 Note: Calling this function asserts that setup is complete 842 and sets the CeedOperator as immutable. 843 844 @param op CeedOperator 845 @param[out] input_fields Variable to store input_fields 846 @param[out] output_fields Variable to store output_fields 847 848 @return An error code: 0 - success, otherwise - failure 849 850 @ref Advanced 851 **/ 852 int CeedOperatorGetFields(CeedOperator op, CeedInt *num_input_fields, 853 CeedOperatorField **input_fields, 854 CeedInt *num_output_fields, 855 CeedOperatorField **output_fields) { 856 int ierr; 857 858 if (op->is_composite) 859 // LCOV_EXCL_START 860 return CeedError(op->ceed, CEED_ERROR_MINOR, 861 "Not defined for composite operator"); 862 // LCOV_EXCL_STOP 863 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 864 865 if (num_input_fields) *num_input_fields = op->qf->num_input_fields; 866 if (input_fields) *input_fields = op->input_fields; 867 if (num_output_fields) *num_output_fields = op->qf->num_output_fields; 868 if (output_fields) *output_fields = op->output_fields; 869 return CEED_ERROR_SUCCESS; 870 } 871 872 /** 873 @brief Get the name of a CeedOperatorField 874 875 @param op_field CeedOperatorField 876 @param[out] field_name Variable to store the field name 877 878 @return An error code: 0 - success, otherwise - failure 879 880 @ref Advanced 881 **/ 882 int CeedOperatorFieldGetName(CeedOperatorField op_field, char **field_name) { 883 *field_name = (char *)op_field->field_name; 884 return CEED_ERROR_SUCCESS; 885 } 886 887 /** 888 @brief Get the CeedElemRestriction of a CeedOperatorField 889 890 @param op_field CeedOperatorField 891 @param[out] rstr Variable to store CeedElemRestriction 892 893 @return An error code: 0 - success, otherwise - failure 894 895 @ref Advanced 896 **/ 897 int CeedOperatorFieldGetElemRestriction(CeedOperatorField op_field, 898 CeedElemRestriction *rstr) { 899 *rstr = op_field->elem_restr; 900 return CEED_ERROR_SUCCESS; 901 } 902 903 /** 904 @brief Get the CeedBasis of a CeedOperatorField 905 906 @param op_field CeedOperatorField 907 @param[out] basis Variable to store CeedBasis 908 909 @return An error code: 0 - success, otherwise - failure 910 911 @ref Advanced 912 **/ 913 int CeedOperatorFieldGetBasis(CeedOperatorField op_field, CeedBasis *basis) { 914 *basis = op_field->basis; 915 return CEED_ERROR_SUCCESS; 916 } 917 918 /** 919 @brief Get the CeedVector of a CeedOperatorField 920 921 @param op_field CeedOperatorField 922 @param[out] vec Variable to store CeedVector 923 924 @return An error code: 0 - success, otherwise - failure 925 926 @ref Advanced 927 **/ 928 int CeedOperatorFieldGetVector(CeedOperatorField op_field, CeedVector *vec) { 929 *vec = op_field->vec; 930 return CEED_ERROR_SUCCESS; 931 } 932 933 /** 934 @brief Add a sub-operator to a composite CeedOperator 935 936 @param[out] composite_op Composite CeedOperator 937 @param sub_op Sub-operator CeedOperator 938 939 @return An error code: 0 - success, otherwise - failure 940 941 @ref User 942 */ 943 int CeedCompositeOperatorAddSub(CeedOperator composite_op, 944 CeedOperator sub_op) { 945 int ierr; 946 947 if (!composite_op->is_composite) 948 // LCOV_EXCL_START 949 return CeedError(composite_op->ceed, CEED_ERROR_MINOR, 950 "CeedOperator is not a composite operator"); 951 // LCOV_EXCL_STOP 952 953 if (composite_op->num_suboperators == CEED_COMPOSITE_MAX) 954 // LCOV_EXCL_START 955 return CeedError(composite_op->ceed, CEED_ERROR_UNSUPPORTED, 956 "Cannot add additional sub_operators"); 957 // LCOV_EXCL_STOP 958 if (composite_op->is_immutable) 959 // LCOV_EXCL_START 960 return CeedError(composite_op->ceed, CEED_ERROR_MAJOR, 961 "Operator cannot be changed after set as immutable"); 962 // LCOV_EXCL_STOP 963 964 composite_op->sub_operators[composite_op->num_suboperators] = sub_op; 965 ierr = CeedOperatorReference(sub_op); CeedChk(ierr); 966 composite_op->num_suboperators++; 967 return CEED_ERROR_SUCCESS; 968 } 969 970 /** 971 @brief Set the number of quadrature points associated with a CeedOperator. 972 This should be used when creating a CeedOperator where every 973 field has a collocated basis. This function cannot be used for 974 composite CeedOperators. 975 976 @param op CeedOperator 977 @param num_qpts Number of quadrature points to set 978 979 @return An error code: 0 - success, otherwise - failure 980 981 @ref Advanced 982 **/ 983 984 int CeedOperatorSetNumQuadraturePoints(CeedOperator op, CeedInt num_qpts) { 985 if (op->is_composite) 986 // LCOV_EXCL_START 987 return CeedError(op->ceed, CEED_ERROR_MINOR, 988 "Not defined for composite operator"); 989 // LCOV_EXCL_STOP 990 if (op->num_qpts) 991 // LCOV_EXCL_START 992 return CeedError(op->ceed, CEED_ERROR_MINOR, 993 "Number of quadrature points already defined"); 994 // LCOV_EXCL_STOP 995 if (op->is_immutable) 996 // LCOV_EXCL_START 997 return CeedError(op->ceed, CEED_ERROR_MAJOR, 998 "Operator cannot be changed after set as immutable"); 999 // LCOV_EXCL_STOP 1000 1001 op->num_qpts = num_qpts; 1002 return CEED_ERROR_SUCCESS; 1003 } 1004 1005 /** 1006 @brief View a CeedOperator 1007 1008 @param[in] op CeedOperator to view 1009 @param[in] stream Stream to write; typically stdout/stderr or a file 1010 1011 @return Error code: 0 - success, otherwise - failure 1012 1013 @ref User 1014 **/ 1015 int CeedOperatorView(CeedOperator op, FILE *stream) { 1016 int ierr; 1017 1018 if (op->is_composite) { 1019 fprintf(stream, "Composite CeedOperator\n"); 1020 1021 for (CeedInt i=0; i<op->num_suboperators; i++) { 1022 fprintf(stream, " SubOperator [%d]:\n", i); 1023 ierr = CeedOperatorSingleView(op->sub_operators[i], 1, stream); 1024 CeedChk(ierr); 1025 } 1026 } else { 1027 fprintf(stream, "CeedOperator\n"); 1028 ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr); 1029 } 1030 return CEED_ERROR_SUCCESS; 1031 } 1032 1033 /** 1034 @brief Apply CeedOperator to a vector 1035 1036 This computes the action of the operator on the specified (active) input, 1037 yielding its (active) output. All inputs and outputs must be specified using 1038 CeedOperatorSetField(). 1039 1040 Note: Calling this function asserts that setup is complete 1041 and sets the CeedOperator as immutable. 1042 1043 @param op CeedOperator to apply 1044 @param[in] in CeedVector containing input state or @ref CEED_VECTOR_NONE if 1045 there are no active inputs 1046 @param[out] out CeedVector to store result of applying operator (must be 1047 distinct from @a in) or @ref CEED_VECTOR_NONE if there are no 1048 active outputs 1049 @param request Address of CeedRequest for non-blocking completion, else 1050 @ref CEED_REQUEST_IMMEDIATE 1051 1052 @return An error code: 0 - success, otherwise - failure 1053 1054 @ref User 1055 **/ 1056 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, 1057 CeedRequest *request) { 1058 int ierr; 1059 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1060 1061 if (op->num_elem) { 1062 // Standard Operator 1063 if (op->Apply) { 1064 ierr = op->Apply(op, in, out, request); CeedChk(ierr); 1065 } else { 1066 // Zero all output vectors 1067 CeedQFunction qf = op->qf; 1068 for (CeedInt i=0; i<qf->num_output_fields; i++) { 1069 CeedVector vec = op->output_fields[i]->vec; 1070 if (vec == CEED_VECTOR_ACTIVE) 1071 vec = out; 1072 if (vec != CEED_VECTOR_NONE) { 1073 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 1074 } 1075 } 1076 // Apply 1077 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 1078 } 1079 } else if (op->is_composite) { 1080 // Composite Operator 1081 if (op->ApplyComposite) { 1082 ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr); 1083 } else { 1084 CeedInt num_suboperators; 1085 ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1086 CeedOperator *sub_operators; 1087 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1088 1089 // Zero all output vectors 1090 if (out != CEED_VECTOR_NONE) { 1091 ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr); 1092 } 1093 for (CeedInt i=0; i<num_suboperators; i++) { 1094 for (CeedInt j=0; j<sub_operators[i]->qf->num_output_fields; j++) { 1095 CeedVector vec = sub_operators[i]->output_fields[j]->vec; 1096 if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) { 1097 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 1098 } 1099 } 1100 } 1101 // Apply 1102 for (CeedInt i=0; i<op->num_suboperators; i++) { 1103 ierr = CeedOperatorApplyAdd(op->sub_operators[i], in, out, request); 1104 CeedChk(ierr); 1105 } 1106 } 1107 } 1108 return CEED_ERROR_SUCCESS; 1109 } 1110 1111 /** 1112 @brief Apply CeedOperator to a vector and add result to output vector 1113 1114 This computes the action of the operator on the specified (active) input, 1115 yielding its (active) output. All inputs and outputs must be specified using 1116 CeedOperatorSetField(). 1117 1118 @param op CeedOperator to apply 1119 @param[in] in CeedVector containing input state or NULL if there are no 1120 active inputs 1121 @param[out] out CeedVector to sum in result of applying operator (must be 1122 distinct from @a in) or NULL if there are no active outputs 1123 @param request Address of CeedRequest for non-blocking completion, else 1124 @ref CEED_REQUEST_IMMEDIATE 1125 1126 @return An error code: 0 - success, otherwise - failure 1127 1128 @ref User 1129 **/ 1130 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, 1131 CeedRequest *request) { 1132 int ierr; 1133 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1134 1135 if (op->num_elem) { 1136 // Standard Operator 1137 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 1138 } else if (op->is_composite) { 1139 // Composite Operator 1140 if (op->ApplyAddComposite) { 1141 ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr); 1142 } else { 1143 CeedInt num_suboperators; 1144 ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1145 CeedOperator *sub_operators; 1146 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1147 1148 for (CeedInt i=0; i<num_suboperators; i++) { 1149 ierr = CeedOperatorApplyAdd(sub_operators[i], in, out, request); 1150 CeedChk(ierr); 1151 } 1152 } 1153 } 1154 return CEED_ERROR_SUCCESS; 1155 } 1156 1157 /** 1158 @brief Destroy a CeedOperator 1159 1160 @param op CeedOperator to destroy 1161 1162 @return An error code: 0 - success, otherwise - failure 1163 1164 @ref User 1165 **/ 1166 int CeedOperatorDestroy(CeedOperator *op) { 1167 int ierr; 1168 1169 if (!*op || --(*op)->ref_count > 0) return CEED_ERROR_SUCCESS; 1170 if ((*op)->Destroy) { 1171 ierr = (*op)->Destroy(*op); CeedChk(ierr); 1172 } 1173 ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr); 1174 // Free fields 1175 for (int i=0; i<(*op)->num_fields; i++) 1176 if ((*op)->input_fields[i]) { 1177 if ((*op)->input_fields[i]->elem_restr != CEED_ELEMRESTRICTION_NONE) { 1178 ierr = CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_restr); 1179 CeedChk(ierr); 1180 } 1181 if ((*op)->input_fields[i]->basis != CEED_BASIS_COLLOCATED) { 1182 ierr = CeedBasisDestroy(&(*op)->input_fields[i]->basis); CeedChk(ierr); 1183 } 1184 if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE && 1185 (*op)->input_fields[i]->vec != CEED_VECTOR_NONE ) { 1186 ierr = CeedVectorDestroy(&(*op)->input_fields[i]->vec); CeedChk(ierr); 1187 } 1188 ierr = CeedFree(&(*op)->input_fields[i]->field_name); CeedChk(ierr); 1189 ierr = CeedFree(&(*op)->input_fields[i]); CeedChk(ierr); 1190 } 1191 for (int i=0; i<(*op)->num_fields; i++) 1192 if ((*op)->output_fields[i]) { 1193 ierr = CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_restr); 1194 CeedChk(ierr); 1195 if ((*op)->output_fields[i]->basis != CEED_BASIS_COLLOCATED) { 1196 ierr = CeedBasisDestroy(&(*op)->output_fields[i]->basis); CeedChk(ierr); 1197 } 1198 if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE && 1199 (*op)->output_fields[i]->vec != CEED_VECTOR_NONE ) { 1200 ierr = CeedVectorDestroy(&(*op)->output_fields[i]->vec); CeedChk(ierr); 1201 } 1202 ierr = CeedFree(&(*op)->output_fields[i]->field_name); CeedChk(ierr); 1203 ierr = CeedFree(&(*op)->output_fields[i]); CeedChk(ierr); 1204 } 1205 // Destroy sub_operators 1206 for (int i=0; i<(*op)->num_suboperators; i++) 1207 if ((*op)->sub_operators[i]) { 1208 ierr = CeedOperatorDestroy(&(*op)->sub_operators[i]); CeedChk(ierr); 1209 } 1210 ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr); 1211 ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr); 1212 ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr); 1213 1214 // Destroy fallback 1215 if ((*op)->op_fallback) { 1216 ierr = (*op)->qf_fallback->Destroy((*op)->qf_fallback); CeedChk(ierr); 1217 ierr = CeedFree(&(*op)->qf_fallback); CeedChk(ierr); 1218 ierr = (*op)->op_fallback->Destroy((*op)->op_fallback); CeedChk(ierr); 1219 ierr = CeedFree(&(*op)->op_fallback); CeedChk(ierr); 1220 } 1221 1222 ierr = CeedFree(&(*op)->input_fields); CeedChk(ierr); 1223 ierr = CeedFree(&(*op)->output_fields); CeedChk(ierr); 1224 ierr = CeedFree(&(*op)->sub_operators); CeedChk(ierr); 1225 ierr = CeedFree(op); CeedChk(ierr); 1226 return CEED_ERROR_SUCCESS; 1227 } 1228 1229 /// @} 1230