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