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 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] num_input_fields Variable to store number of input fields 723 @param[out] input_fields Variable to store input_fields 724 @param[out] num_output_fields Variable to store number of output fields 725 @param[out] output_fields Variable to store output_fields 726 727 @return An error code: 0 - success, otherwise - failure 728 729 @ref Advanced 730 **/ 731 int CeedOperatorGetFields(CeedOperator op, CeedInt *num_input_fields, 732 CeedOperatorField **input_fields, 733 CeedInt *num_output_fields, 734 CeedOperatorField **output_fields) { 735 int ierr; 736 737 if (op->is_composite) 738 // LCOV_EXCL_START 739 return CeedError(op->ceed, CEED_ERROR_MINOR, 740 "Not defined for composite operator"); 741 // LCOV_EXCL_STOP 742 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 743 744 if (num_input_fields) *num_input_fields = op->qf->num_input_fields; 745 if (input_fields) *input_fields = op->input_fields; 746 if (num_output_fields) *num_output_fields = op->qf->num_output_fields; 747 if (output_fields) *output_fields = op->output_fields; 748 return CEED_ERROR_SUCCESS; 749 } 750 751 /** 752 @brief Get the name of a CeedOperatorField 753 754 @param op_field CeedOperatorField 755 @param[out] field_name Variable to store the field name 756 757 @return An error code: 0 - success, otherwise - failure 758 759 @ref Advanced 760 **/ 761 int CeedOperatorFieldGetName(CeedOperatorField op_field, char **field_name) { 762 *field_name = (char *)op_field->field_name; 763 return CEED_ERROR_SUCCESS; 764 } 765 766 /** 767 @brief Get the CeedElemRestriction of a CeedOperatorField 768 769 @param op_field CeedOperatorField 770 @param[out] rstr Variable to store CeedElemRestriction 771 772 @return An error code: 0 - success, otherwise - failure 773 774 @ref Advanced 775 **/ 776 int CeedOperatorFieldGetElemRestriction(CeedOperatorField op_field, 777 CeedElemRestriction *rstr) { 778 *rstr = op_field->elem_restr; 779 return CEED_ERROR_SUCCESS; 780 } 781 782 /** 783 @brief Get the CeedBasis of a CeedOperatorField 784 785 @param op_field CeedOperatorField 786 @param[out] basis Variable to store CeedBasis 787 788 @return An error code: 0 - success, otherwise - failure 789 790 @ref Advanced 791 **/ 792 int CeedOperatorFieldGetBasis(CeedOperatorField op_field, CeedBasis *basis) { 793 *basis = op_field->basis; 794 return CEED_ERROR_SUCCESS; 795 } 796 797 /** 798 @brief Get the CeedVector of a CeedOperatorField 799 800 @param op_field CeedOperatorField 801 @param[out] vec Variable to store CeedVector 802 803 @return An error code: 0 - success, otherwise - failure 804 805 @ref Advanced 806 **/ 807 int CeedOperatorFieldGetVector(CeedOperatorField op_field, CeedVector *vec) { 808 *vec = op_field->vec; 809 return CEED_ERROR_SUCCESS; 810 } 811 812 /** 813 @brief Add a sub-operator to a composite CeedOperator 814 815 @param[out] composite_op Composite CeedOperator 816 @param sub_op Sub-operator CeedOperator 817 818 @return An error code: 0 - success, otherwise - failure 819 820 @ref User 821 */ 822 int CeedCompositeOperatorAddSub(CeedOperator composite_op, 823 CeedOperator sub_op) { 824 int ierr; 825 826 if (!composite_op->is_composite) 827 // LCOV_EXCL_START 828 return CeedError(composite_op->ceed, CEED_ERROR_MINOR, 829 "CeedOperator is not a composite operator"); 830 // LCOV_EXCL_STOP 831 832 if (composite_op->num_suboperators == CEED_COMPOSITE_MAX) 833 // LCOV_EXCL_START 834 return CeedError(composite_op->ceed, CEED_ERROR_UNSUPPORTED, 835 "Cannot add additional sub_operators"); 836 // LCOV_EXCL_STOP 837 if (composite_op->is_immutable) 838 // LCOV_EXCL_START 839 return CeedError(composite_op->ceed, CEED_ERROR_MAJOR, 840 "Operator cannot be changed after set as immutable"); 841 // LCOV_EXCL_STOP 842 843 composite_op->sub_operators[composite_op->num_suboperators] = sub_op; 844 ierr = CeedOperatorReference(sub_op); CeedChk(ierr); 845 composite_op->num_suboperators++; 846 return CEED_ERROR_SUCCESS; 847 } 848 849 /** 850 @brief Check if a CeedOperator is ready to be used. 851 852 @param[in] op CeedOperator to check 853 854 @return An error code: 0 - success, otherwise - failure 855 856 @ref User 857 **/ 858 int CeedOperatorCheckReady(CeedOperator op) { 859 int ierr; 860 Ceed ceed; 861 ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); 862 863 if (op->is_interface_setup) 864 return CEED_ERROR_SUCCESS; 865 866 CeedQFunction qf = op->qf; 867 if (op->is_composite) { 868 if (!op->num_suboperators) 869 // LCOV_EXCL_START 870 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No sub_operators set"); 871 // LCOV_EXCL_STOP 872 for (CeedInt i = 0; i < op->num_suboperators; i++) { 873 ierr = CeedOperatorCheckReady(op->sub_operators[i]); CeedChk(ierr); 874 } 875 } else { 876 if (op->num_fields == 0) 877 // LCOV_EXCL_START 878 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No operator fields set"); 879 // LCOV_EXCL_STOP 880 if (op->num_fields < qf->num_input_fields + qf->num_output_fields) 881 // LCOV_EXCL_START 882 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set"); 883 // LCOV_EXCL_STOP 884 if (!op->has_restriction) 885 // LCOV_EXCL_START 886 return CeedError(ceed, CEED_ERROR_INCOMPLETE, 887 "At least one restriction required"); 888 // LCOV_EXCL_STOP 889 if (op->num_qpts == 0) 890 // LCOV_EXCL_START 891 return CeedError(ceed, CEED_ERROR_INCOMPLETE, 892 "At least one non-collocated basis is required " 893 "or the number of quadrature points must be set"); 894 // LCOV_EXCL_STOP 895 } 896 897 // Flag as immutable and ready 898 op->is_interface_setup = true; 899 if (op->qf && op->qf != CEED_QFUNCTION_NONE) 900 // LCOV_EXCL_START 901 op->qf->is_immutable = true; 902 // LCOV_EXCL_STOP 903 if (op->dqf && op->dqf != CEED_QFUNCTION_NONE) 904 // LCOV_EXCL_START 905 op->dqf->is_immutable = true; 906 // LCOV_EXCL_STOP 907 if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE) 908 // LCOV_EXCL_START 909 op->dqfT->is_immutable = true; 910 // LCOV_EXCL_STOP 911 return CEED_ERROR_SUCCESS; 912 } 913 914 /** 915 @brief Set the number of quadrature points associated with a CeedOperator. 916 This should be used when creating a CeedOperator where every 917 field has a collocated basis. This function cannot be used for 918 composite CeedOperators. 919 920 @param op CeedOperator 921 @param num_qpts Number of quadrature points to set 922 923 @return An error code: 0 - success, otherwise - failure 924 925 @ref Advanced 926 **/ 927 int CeedOperatorSetNumQuadraturePoints(CeedOperator op, CeedInt num_qpts) { 928 if (op->is_composite) 929 // LCOV_EXCL_START 930 return CeedError(op->ceed, CEED_ERROR_MINOR, 931 "Not defined for composite operator"); 932 // LCOV_EXCL_STOP 933 if (op->num_qpts) 934 // LCOV_EXCL_START 935 return CeedError(op->ceed, CEED_ERROR_MINOR, 936 "Number of quadrature points already defined"); 937 // LCOV_EXCL_STOP 938 if (op->is_immutable) 939 // LCOV_EXCL_START 940 return CeedError(op->ceed, CEED_ERROR_MAJOR, 941 "Operator cannot be changed after set as immutable"); 942 // LCOV_EXCL_STOP 943 944 op->num_qpts = num_qpts; 945 return CEED_ERROR_SUCCESS; 946 } 947 948 /** 949 @brief View a CeedOperator 950 951 @param[in] op CeedOperator to view 952 @param[in] stream Stream to write; typically stdout/stderr or a file 953 954 @return Error code: 0 - success, otherwise - failure 955 956 @ref User 957 **/ 958 int CeedOperatorView(CeedOperator op, FILE *stream) { 959 int ierr; 960 961 if (op->is_composite) { 962 fprintf(stream, "Composite CeedOperator\n"); 963 964 for (CeedInt i=0; i<op->num_suboperators; i++) { 965 fprintf(stream, " SubOperator [%d]:\n", i); 966 ierr = CeedOperatorSingleView(op->sub_operators[i], 1, stream); 967 CeedChk(ierr); 968 } 969 } else { 970 fprintf(stream, "CeedOperator\n"); 971 ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr); 972 } 973 return CEED_ERROR_SUCCESS; 974 } 975 976 /** 977 @brief Get the Ceed associated with a CeedOperator 978 979 @param op CeedOperator 980 @param[out] ceed Variable to store Ceed 981 982 @return An error code: 0 - success, otherwise - failure 983 984 @ref Advanced 985 **/ 986 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) { 987 *ceed = op->ceed; 988 return CEED_ERROR_SUCCESS; 989 } 990 991 /** 992 @brief Get the number of elements associated with a CeedOperator 993 994 @param op CeedOperator 995 @param[out] num_elem Variable to store number of elements 996 997 @return An error code: 0 - success, otherwise - failure 998 999 @ref Advanced 1000 **/ 1001 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) { 1002 if (op->is_composite) 1003 // LCOV_EXCL_START 1004 return CeedError(op->ceed, CEED_ERROR_MINOR, 1005 "Not defined for composite operator"); 1006 // LCOV_EXCL_STOP 1007 1008 *num_elem = op->num_elem; 1009 return CEED_ERROR_SUCCESS; 1010 } 1011 1012 /** 1013 @brief Get the number of quadrature points associated with a CeedOperator 1014 1015 @param op CeedOperator 1016 @param[out] num_qpts Variable to store vector number of quadrature points 1017 1018 @return An error code: 0 - success, otherwise - failure 1019 1020 @ref Advanced 1021 **/ 1022 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) { 1023 if (op->is_composite) 1024 // LCOV_EXCL_START 1025 return CeedError(op->ceed, CEED_ERROR_MINOR, 1026 "Not defined for composite operator"); 1027 // LCOV_EXCL_STOP 1028 1029 *num_qpts = op->num_qpts; 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 = CeedVectorDestroy(&(*op)->op_fallback->qf_assembled); CeedChk(ierr); 1219 ierr = CeedElemRestrictionDestroy(&(*op)->op_fallback->qf_assembled_rstr); 1220 CeedChk(ierr); 1221 ierr = (*op)->op_fallback->Destroy((*op)->op_fallback); CeedChk(ierr); 1222 ierr = CeedFree(&(*op)->op_fallback); CeedChk(ierr); 1223 } 1224 1225 // Destroy QF assembly cache 1226 ierr = CeedVectorDestroy(&(*op)->qf_assembled); CeedChk(ierr); 1227 ierr = CeedElemRestrictionDestroy(&(*op)->qf_assembled_rstr); CeedChk(ierr); 1228 1229 ierr = CeedFree(&(*op)->input_fields); CeedChk(ierr); 1230 ierr = CeedFree(&(*op)->output_fields); CeedChk(ierr); 1231 ierr = CeedFree(&(*op)->sub_operators); CeedChk(ierr); 1232 ierr = CeedFree(op); CeedChk(ierr); 1233 return CEED_ERROR_SUCCESS; 1234 } 1235 1236 /// @} 1237