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