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