1 // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at 2 // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights 3 // reserved. See files LICENSE and NOTICE for details. 4 // 5 // This file is part of CEED, a collection of benchmarks, miniapps, software 6 // libraries and APIs for efficient high-order finite element and spectral 7 // element discretizations for exascale applications. For more information and 8 // source code availability see http://github.com/ceed. 9 // 10 // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC, 11 // a collaborative effort of two U.S. Department of Energy organizations (Office 12 // of Science and the National Nuclear Security Administration) responsible for 13 // the planning and preparation of a capable exascale ecosystem, including 14 // software, applications, hardware, advanced system engineering and early 15 // testbed platforms, in support of the nation's exascale computing imperative. 16 17 #include <ceed/ceed.h> 18 #include <ceed/backend.h> 19 #include <ceed-impl.h> 20 #include <math.h> 21 #include <stdbool.h> 22 #include <stdio.h> 23 #include <string.h> 24 25 /// @file 26 /// Implementation of CeedOperator interfaces 27 28 /// ---------------------------------------------------------------------------- 29 /// CeedOperator Library Internal Functions 30 /// ---------------------------------------------------------------------------- 31 /// @addtogroup CeedOperatorDeveloper 32 /// @{ 33 34 /** 35 @brief Check if a CeedOperator Field matches the QFunction Field 36 37 @param[in] ceed Ceed object for error handling 38 @param[in] qf_field QFunction Field matching Operator Field 39 @param[in] r Operator Field ElemRestriction 40 @param[in] b Operator Field Basis 41 42 @return An error code: 0 - success, otherwise - failure 43 44 @ref Developer 45 **/ 46 static int CeedOperatorCheckField(Ceed ceed, CeedQFunctionField qf_field, 47 CeedElemRestriction r, CeedBasis b) { 48 int ierr; 49 CeedEvalMode eval_mode = qf_field->eval_mode; 50 CeedInt dim = 1, num_comp = 1, restr_num_comp = 1, size = qf_field->size; 51 // Restriction 52 if (r != CEED_ELEMRESTRICTION_NONE) { 53 if (eval_mode == CEED_EVAL_WEIGHT) { 54 // LCOV_EXCL_START 55 return CeedError(ceed, CEED_ERROR_INCOMPATIBLE, 56 "CEED_ELEMRESTRICTION_NONE should be used " 57 "for a field with eval mode CEED_EVAL_WEIGHT"); 58 // LCOV_EXCL_STOP 59 } 60 ierr = CeedElemRestrictionGetNumComponents(r, &restr_num_comp); 61 CeedChk(ierr); 62 } 63 if ((r == CEED_ELEMRESTRICTION_NONE) != (eval_mode == CEED_EVAL_WEIGHT)) { 64 // LCOV_EXCL_START 65 return CeedError(ceed, CEED_ERROR_INCOMPATIBLE, 66 "CEED_ELEMRESTRICTION_NONE and CEED_EVAL_WEIGHT " 67 "must be used together."); 68 // LCOV_EXCL_STOP 69 } 70 // Basis 71 if (b != CEED_BASIS_COLLOCATED) { 72 if (eval_mode == CEED_EVAL_NONE) 73 // LCOV_EXCL_START 74 return CeedError(ceed, CEED_ERROR_INCOMPATIBLE, 75 "Field '%s' configured with CEED_EVAL_NONE must " 76 "be used with CEED_BASIS_COLLOCATED", 77 // LCOV_EXCL_STOP 78 qf_field->field_name); 79 ierr = CeedBasisGetDimension(b, &dim); CeedChk(ierr); 80 ierr = CeedBasisGetNumComponents(b, &num_comp); CeedChk(ierr); 81 if (r != CEED_ELEMRESTRICTION_NONE && restr_num_comp != num_comp) { 82 // LCOV_EXCL_START 83 return CeedError(ceed, CEED_ERROR_DIMENSION, 84 "Field '%s' of size %d and EvalMode %s: ElemRestriction " 85 "has %d components, but Basis has %d components", 86 qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], 87 restr_num_comp, 88 num_comp); 89 // LCOV_EXCL_STOP 90 } 91 } 92 // Field size 93 switch(eval_mode) { 94 case CEED_EVAL_NONE: 95 if (size != restr_num_comp) 96 // LCOV_EXCL_START 97 return CeedError(ceed, CEED_ERROR_DIMENSION, 98 "Field '%s' of size %d and EvalMode %s: ElemRestriction has %d components", 99 qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], 100 restr_num_comp); 101 // LCOV_EXCL_STOP 102 break; 103 case CEED_EVAL_INTERP: 104 if (size != num_comp) 105 // LCOV_EXCL_START 106 return CeedError(ceed, CEED_ERROR_DIMENSION, 107 "Field '%s' of size %d and EvalMode %s: ElemRestriction/Basis has %d components", 108 qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], 109 num_comp); 110 // LCOV_EXCL_STOP 111 break; 112 case CEED_EVAL_GRAD: 113 if (size != num_comp * dim) 114 // LCOV_EXCL_START 115 return CeedError(ceed, CEED_ERROR_DIMENSION, 116 "Field '%s' of size %d and EvalMode %s in %d dimensions: " 117 "ElemRestriction/Basis has %d components", 118 qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], dim, 119 num_comp); 120 // LCOV_EXCL_STOP 121 break; 122 case CEED_EVAL_WEIGHT: 123 // No additional checks required 124 break; 125 case CEED_EVAL_DIV: 126 // Not implemented 127 break; 128 case CEED_EVAL_CURL: 129 // Not implemented 130 break; 131 } 132 return CEED_ERROR_SUCCESS; 133 } 134 135 /** 136 @brief Check if a CeedOperator is ready to be used. 137 138 @param[in] op CeedOperator to check 139 140 @return An error code: 0 - success, otherwise - failure 141 142 @ref Developer 143 **/ 144 int CeedOperatorCheckReady(CeedOperator op) { 145 int ierr; 146 Ceed ceed; 147 ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); 148 149 if (op->is_interface_setup) 150 return CEED_ERROR_SUCCESS; 151 152 CeedQFunction qf = op->qf; 153 if (op->is_composite) { 154 if (!op->num_suboperators) 155 // LCOV_EXCL_START 156 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No sub_operators set"); 157 // LCOV_EXCL_STOP 158 } else { 159 if (op->num_fields == 0) 160 // LCOV_EXCL_START 161 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No operator fields set"); 162 // LCOV_EXCL_STOP 163 if (op->num_fields < qf->num_input_fields + qf->num_output_fields) 164 // LCOV_EXCL_START 165 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set"); 166 // LCOV_EXCL_STOP 167 if (!op->has_restriction) 168 // LCOV_EXCL_START 169 return CeedError(ceed, CEED_ERROR_INCOMPLETE, 170 "At least one restriction required"); 171 // LCOV_EXCL_STOP 172 if (op->num_qpts == 0) 173 // LCOV_EXCL_START 174 return CeedError(ceed, CEED_ERROR_INCOMPLETE, 175 "At least one non-collocated basis is required " 176 "or the number of quadrature points must be set"); 177 // LCOV_EXCL_STOP 178 } 179 180 // Flag as immutable and ready 181 op->is_interface_setup = true; 182 if (op->qf && op->qf != CEED_QFUNCTION_NONE) 183 // LCOV_EXCL_START 184 op->qf->is_immutable = true; 185 // LCOV_EXCL_STOP 186 if (op->dqf && op->dqf != CEED_QFUNCTION_NONE) 187 // LCOV_EXCL_START 188 op->dqf->is_immutable = true; 189 // LCOV_EXCL_STOP 190 if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE) 191 // LCOV_EXCL_START 192 op->dqfT->is_immutable = true; 193 // LCOV_EXCL_STOP 194 return CEED_ERROR_SUCCESS; 195 } 196 197 /** 198 @brief View a field of a CeedOperator 199 200 @param[in] field Operator field to view 201 @param[in] qf_field QFunction field (carries field name) 202 @param[in] field_number Number of field being viewed 203 @param[in] sub true indicates sub-operator, which increases indentation; false for top-level operator 204 @param[in] input true for an input field; false for output field 205 @param[in] stream Stream to view to, e.g., stdout 206 207 @return An error code: 0 - success, otherwise - failure 208 209 @ref Utility 210 **/ 211 static int CeedOperatorFieldView(CeedOperatorField field, 212 CeedQFunctionField qf_field, 213 CeedInt field_number, bool sub, bool input, 214 FILE *stream) { 215 const char *pre = sub ? " " : ""; 216 const char *in_out = input ? "Input" : "Output"; 217 218 fprintf(stream, "%s %s Field [%d]:\n" 219 "%s Name: \"%s\"\n", 220 pre, in_out, field_number, pre, qf_field->field_name); 221 222 if (field->basis == CEED_BASIS_COLLOCATED) 223 fprintf(stream, "%s Collocated basis\n", pre); 224 225 if (field->vec == CEED_VECTOR_ACTIVE) 226 fprintf(stream, "%s Active vector\n", pre); 227 else if (field->vec == CEED_VECTOR_NONE) 228 fprintf(stream, "%s No vector\n", pre); 229 return CEED_ERROR_SUCCESS; 230 } 231 232 /** 233 @brief View a single CeedOperator 234 235 @param[in] op CeedOperator to view 236 @param[in] sub Boolean flag for sub-operator 237 @param[in] stream Stream to write; typically stdout/stderr or a file 238 239 @return Error code: 0 - success, otherwise - failure 240 241 @ref Utility 242 **/ 243 int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) { 244 int ierr; 245 const char *pre = sub ? " " : ""; 246 247 CeedInt total_fields = 0; 248 ierr = CeedOperatorGetNumArgs(op, &total_fields); CeedChk(ierr); 249 250 fprintf(stream, "%s %d Field%s\n", pre, total_fields, 251 total_fields>1 ? "s" : ""); 252 253 fprintf(stream, "%s %d Input Field%s:\n", pre, op->qf->num_input_fields, 254 op->qf->num_input_fields>1 ? "s" : ""); 255 for (CeedInt i=0; i<op->qf->num_input_fields; i++) { 256 ierr = CeedOperatorFieldView(op->input_fields[i], op->qf->input_fields[i], 257 i, sub, 1, stream); CeedChk(ierr); 258 } 259 260 fprintf(stream, "%s %d Output Field%s:\n", pre, op->qf->num_output_fields, 261 op->qf->num_output_fields>1 ? "s" : ""); 262 for (CeedInt i=0; i<op->qf->num_output_fields; i++) { 263 ierr = CeedOperatorFieldView(op->output_fields[i], op->qf->output_fields[i], 264 i, sub, 0, stream); CeedChk(ierr); 265 } 266 return CEED_ERROR_SUCCESS; 267 } 268 269 /** 270 @brief Find the active vector basis for a CeedOperator 271 272 @param[in] op CeedOperator to find active basis for 273 @param[out] active_basis Basis for active input vector 274 275 @return An error code: 0 - success, otherwise - failure 276 277 @ ref Developer 278 **/ 279 int CeedOperatorGetActiveBasis(CeedOperator op, CeedBasis *active_basis) { 280 *active_basis = NULL; 281 for (int i = 0; i < op->qf->num_input_fields; i++) 282 if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) { 283 *active_basis = op->input_fields[i]->basis; 284 break; 285 } 286 287 if (!*active_basis) { 288 // LCOV_EXCL_START 289 int ierr; 290 Ceed ceed; 291 ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); 292 return CeedError(ceed, CEED_ERROR_MINOR, 293 "No active CeedBasis found"); 294 // LCOV_EXCL_STOP 295 } 296 return CEED_ERROR_SUCCESS; 297 } 298 299 /** 300 @brief Find the active vector ElemRestriction for a CeedOperator 301 302 @param[in] op CeedOperator to find active basis for 303 @param[out] active_rstr ElemRestriction for active input vector 304 305 @return An error code: 0 - success, otherwise - failure 306 307 @ref Utility 308 **/ 309 int CeedOperatorGetActiveElemRestriction(CeedOperator op, 310 CeedElemRestriction *active_rstr) { 311 *active_rstr = NULL; 312 for (int i = 0; i < op->qf->num_input_fields; i++) 313 if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) { 314 *active_rstr = op->input_fields[i]->elem_restr; 315 break; 316 } 317 318 if (!*active_rstr) { 319 // LCOV_EXCL_START 320 int ierr; 321 Ceed ceed; 322 ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); 323 return CeedError(ceed, CEED_ERROR_INCOMPLETE, 324 "No active CeedElemRestriction found"); 325 // LCOV_EXCL_STOP 326 } 327 return CEED_ERROR_SUCCESS; 328 } 329 330 /// @} 331 332 /// ---------------------------------------------------------------------------- 333 /// CeedOperator Backend API 334 /// ---------------------------------------------------------------------------- 335 /// @addtogroup CeedOperatorBackend 336 /// @{ 337 338 /** 339 @brief Get the number of arguments associated with a CeedOperator 340 341 @param op CeedOperator 342 @param[out] num_args Variable to store vector number of arguments 343 344 @return An error code: 0 - success, otherwise - failure 345 346 @ref Backend 347 **/ 348 349 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *num_args) { 350 if (op->is_composite) 351 // LCOV_EXCL_START 352 return CeedError(op->ceed, CEED_ERROR_MINOR, 353 "Not defined for composite operators"); 354 // LCOV_EXCL_STOP 355 356 *num_args = op->num_fields; 357 return CEED_ERROR_SUCCESS; 358 } 359 360 /** 361 @brief Get the setup status of a CeedOperator 362 363 @param op CeedOperator 364 @param[out] is_setup_done Variable to store setup status 365 366 @return An error code: 0 - success, otherwise - failure 367 368 @ref Backend 369 **/ 370 371 int CeedOperatorIsSetupDone(CeedOperator op, bool *is_setup_done) { 372 *is_setup_done = op->is_backend_setup; 373 return CEED_ERROR_SUCCESS; 374 } 375 376 /** 377 @brief Get the QFunction associated with a CeedOperator 378 379 @param op CeedOperator 380 @param[out] qf Variable to store QFunction 381 382 @return An error code: 0 - success, otherwise - failure 383 384 @ref Backend 385 **/ 386 387 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) { 388 if (op->is_composite) 389 // LCOV_EXCL_START 390 return CeedError(op->ceed, CEED_ERROR_MINOR, 391 "Not defined for composite operator"); 392 // LCOV_EXCL_STOP 393 394 *qf = op->qf; 395 return CEED_ERROR_SUCCESS; 396 } 397 398 /** 399 @brief Get a boolean value indicating if the CeedOperator is composite 400 401 @param op CeedOperator 402 @param[out] is_composite Variable to store composite status 403 404 @return An error code: 0 - success, otherwise - failure 405 406 @ref Backend 407 **/ 408 409 int CeedOperatorIsComposite(CeedOperator op, bool *is_composite) { 410 *is_composite = op->is_composite; 411 return CEED_ERROR_SUCCESS; 412 } 413 414 /** 415 @brief Get the number of sub_operators associated with a CeedOperator 416 417 @param op CeedOperator 418 @param[out] num_suboperators Variable to store number of sub_operators 419 420 @return An error code: 0 - success, otherwise - failure 421 422 @ref Backend 423 **/ 424 425 int CeedOperatorGetNumSub(CeedOperator op, CeedInt *num_suboperators) { 426 if (!op->is_composite) 427 // LCOV_EXCL_START 428 return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator"); 429 // LCOV_EXCL_STOP 430 431 *num_suboperators = op->num_suboperators; 432 return CEED_ERROR_SUCCESS; 433 } 434 435 /** 436 @brief Get the list of sub_operators associated with a CeedOperator 437 438 @param op CeedOperator 439 @param[out] sub_operators Variable to store list of sub_operators 440 441 @return An error code: 0 - success, otherwise - failure 442 443 @ref Backend 444 **/ 445 446 int CeedOperatorGetSubList(CeedOperator op, CeedOperator **sub_operators) { 447 if (!op->is_composite) 448 // LCOV_EXCL_START 449 return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator"); 450 // LCOV_EXCL_STOP 451 452 *sub_operators = op->sub_operators; 453 return CEED_ERROR_SUCCESS; 454 } 455 456 /** 457 @brief Get the backend data of a CeedOperator 458 459 @param op CeedOperator 460 @param[out] data Variable to store data 461 462 @return An error code: 0 - success, otherwise - failure 463 464 @ref Backend 465 **/ 466 467 int CeedOperatorGetData(CeedOperator op, void *data) { 468 *(void **)data = op->data; 469 return CEED_ERROR_SUCCESS; 470 } 471 472 /** 473 @brief Set the backend data of a CeedOperator 474 475 @param[out] op CeedOperator 476 @param data Data to set 477 478 @return An error code: 0 - success, otherwise - failure 479 480 @ref Backend 481 **/ 482 483 int CeedOperatorSetData(CeedOperator op, void *data) { 484 op->data = data; 485 return CEED_ERROR_SUCCESS; 486 } 487 488 /** 489 @brief Increment the reference counter for a CeedOperator 490 491 @param op CeedOperator to increment the reference counter 492 493 @return An error code: 0 - success, otherwise - failure 494 495 @ref Backend 496 **/ 497 int CeedOperatorReference(CeedOperator op) { 498 op->ref_count++; 499 return CEED_ERROR_SUCCESS; 500 } 501 502 /** 503 @brief Set the setup flag of a CeedOperator to True 504 505 @param op CeedOperator 506 507 @return An error code: 0 - success, otherwise - failure 508 509 @ref Backend 510 **/ 511 512 int CeedOperatorSetSetupDone(CeedOperator op) { 513 op->is_backend_setup = true; 514 return CEED_ERROR_SUCCESS; 515 } 516 517 /// @} 518 519 /// ---------------------------------------------------------------------------- 520 /// CeedOperator Public API 521 /// ---------------------------------------------------------------------------- 522 /// @addtogroup CeedOperatorUser 523 /// @{ 524 525 /** 526 @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and 527 CeedElemRestriction can be associated with CeedQFunction fields with 528 \ref CeedOperatorSetField. 529 530 @param ceed A Ceed object where the CeedOperator will be created 531 @param qf QFunction defining the action of the operator at quadrature points 532 @param dqf QFunction defining the action of the Jacobian of @a qf (or 533 @ref CEED_QFUNCTION_NONE) 534 @param dqfT QFunction defining the action of the transpose of the Jacobian 535 of @a qf (or @ref CEED_QFUNCTION_NONE) 536 @param[out] op Address of the variable where the newly created 537 CeedOperator will be stored 538 539 @return An error code: 0 - success, otherwise - failure 540 541 @ref User 542 */ 543 int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, 544 CeedQFunction dqfT, CeedOperator *op) { 545 int ierr; 546 547 if (!ceed->OperatorCreate) { 548 Ceed delegate; 549 ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr); 550 551 if (!delegate) 552 // LCOV_EXCL_START 553 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 554 "Backend does not support OperatorCreate"); 555 // LCOV_EXCL_STOP 556 557 ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr); 558 return CEED_ERROR_SUCCESS; 559 } 560 561 if (!qf || qf == CEED_QFUNCTION_NONE) 562 // LCOV_EXCL_START 563 return CeedError(ceed, CEED_ERROR_MINOR, 564 "Operator must have a valid QFunction."); 565 // LCOV_EXCL_STOP 566 ierr = CeedCalloc(1, op); CeedChk(ierr); 567 (*op)->ceed = ceed; 568 ierr = CeedReference(ceed); CeedChk(ierr); 569 (*op)->ref_count = 1; 570 (*op)->qf = qf; 571 ierr = CeedQFunctionReference(qf); CeedChk(ierr); 572 if (dqf && dqf != CEED_QFUNCTION_NONE) { 573 (*op)->dqf = dqf; 574 ierr = CeedQFunctionReference(dqf); CeedChk(ierr); 575 } 576 if (dqfT && dqfT != CEED_QFUNCTION_NONE) { 577 (*op)->dqfT = dqfT; 578 ierr = CeedQFunctionReference(dqfT); CeedChk(ierr); 579 } 580 ierr = CeedCalloc(16, &(*op)->input_fields); CeedChk(ierr); 581 ierr = CeedCalloc(16, &(*op)->output_fields); CeedChk(ierr); 582 ierr = ceed->OperatorCreate(*op); CeedChk(ierr); 583 return CEED_ERROR_SUCCESS; 584 } 585 586 /** 587 @brief Create an operator that composes the action of several operators 588 589 @param ceed A Ceed object where the CeedOperator will be created 590 @param[out] op Address of the variable where the newly created 591 Composite CeedOperator will be stored 592 593 @return An error code: 0 - success, otherwise - failure 594 595 @ref User 596 */ 597 int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) { 598 int ierr; 599 600 if (!ceed->CompositeOperatorCreate) { 601 Ceed delegate; 602 ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr); 603 604 if (delegate) { 605 ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr); 606 return CEED_ERROR_SUCCESS; 607 } 608 } 609 610 ierr = CeedCalloc(1, op); CeedChk(ierr); 611 (*op)->ceed = ceed; 612 ierr = CeedReference(ceed); CeedChk(ierr); 613 (*op)->is_composite = true; 614 ierr = CeedCalloc(16, &(*op)->sub_operators); CeedChk(ierr); 615 616 if (ceed->CompositeOperatorCreate) { 617 ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr); 618 } 619 return CEED_ERROR_SUCCESS; 620 } 621 622 /** 623 @brief Copy the pointer to a CeedOperator. Both pointers should 624 be destroyed with `CeedOperatorDestroy()`; 625 Note: If `*op_copy` is non-NULL, then it is assumed that 626 `*op_copy` is a pointer to a CeedOperator. This 627 CeedOperator will be destroyed if `*op_copy` is the only 628 reference to this CeedOperator. 629 630 @param op CeedOperator to copy reference to 631 @param[out] op_copy Variable to store copied reference 632 633 @return An error code: 0 - success, otherwise - failure 634 635 @ref User 636 **/ 637 int CeedOperatorReferenceCopy(CeedOperator op, CeedOperator *op_copy) { 638 int ierr; 639 640 ierr = CeedOperatorReference(op); CeedChk(ierr); 641 ierr = CeedOperatorDestroy(op_copy); CeedChk(ierr); 642 *op_copy = op; 643 return CEED_ERROR_SUCCESS; 644 } 645 646 /** 647 @brief Provide a field to a CeedOperator for use by its CeedQFunction 648 649 This function is used to specify both active and passive fields to a 650 CeedOperator. For passive fields, a vector @arg v must be provided. Passive 651 fields can inputs or outputs (updated in-place when operator is applied). 652 653 Active fields must be specified using this function, but their data (in a 654 CeedVector) is passed in CeedOperatorApply(). There can be at most one active 655 input and at most one active output. 656 657 @param op CeedOperator on which to provide the field 658 @param field_name Name of the field (to be matched with the name used by 659 CeedQFunction) 660 @param r CeedElemRestriction 661 @param b CeedBasis in which the field resides or @ref CEED_BASIS_COLLOCATED 662 if collocated with quadrature points 663 @param v CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE 664 if field is active or @ref CEED_VECTOR_NONE if using 665 @ref CEED_EVAL_WEIGHT in the QFunction 666 667 @return An error code: 0 - success, otherwise - failure 668 669 @ref User 670 **/ 671 int CeedOperatorSetField(CeedOperator op, const char *field_name, 672 CeedElemRestriction r, CeedBasis b, CeedVector v) { 673 int ierr; 674 if (op->is_composite) 675 // LCOV_EXCL_START 676 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 677 "Cannot add field to composite operator."); 678 // LCOV_EXCL_STOP 679 if (op->is_immutable) 680 // LCOV_EXCL_START 681 return CeedError(op->ceed, CEED_ERROR_MAJOR, 682 "Operator cannot be changed after set as immutable"); 683 // LCOV_EXCL_STOP 684 if (!r) 685 // LCOV_EXCL_START 686 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 687 "ElemRestriction r for field \"%s\" must be non-NULL.", 688 field_name); 689 // LCOV_EXCL_STOP 690 if (!b) 691 // LCOV_EXCL_START 692 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 693 "Basis b for field \"%s\" must be non-NULL.", 694 field_name); 695 // LCOV_EXCL_STOP 696 if (!v) 697 // LCOV_EXCL_START 698 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 699 "Vector v for field \"%s\" must be non-NULL.", 700 field_name); 701 // LCOV_EXCL_STOP 702 703 CeedInt num_elem; 704 ierr = CeedElemRestrictionGetNumElements(r, &num_elem); CeedChk(ierr); 705 if (r != CEED_ELEMRESTRICTION_NONE && op->has_restriction && 706 op->num_elem != num_elem) 707 // LCOV_EXCL_START 708 return CeedError(op->ceed, CEED_ERROR_DIMENSION, 709 "ElemRestriction with %d elements incompatible with prior " 710 "%d elements", num_elem, op->num_elem); 711 // LCOV_EXCL_STOP 712 713 CeedInt num_qpts = 0; 714 if (b != CEED_BASIS_COLLOCATED) { 715 ierr = CeedBasisGetNumQuadraturePoints(b, &num_qpts); CeedChk(ierr); 716 if (op->num_qpts && op->num_qpts != num_qpts) 717 // LCOV_EXCL_START 718 return CeedError(op->ceed, CEED_ERROR_DIMENSION, 719 "Basis with %d quadrature points " 720 "incompatible with prior %d points", num_qpts, 721 op->num_qpts); 722 // LCOV_EXCL_STOP 723 } 724 CeedQFunctionField qf_field; 725 CeedOperatorField *op_field; 726 for (CeedInt i=0; i<op->qf->num_input_fields; i++) { 727 if (!strcmp(field_name, (*op->qf->input_fields[i]).field_name)) { 728 qf_field = op->qf->input_fields[i]; 729 op_field = &op->input_fields[i]; 730 goto found; 731 } 732 } 733 for (CeedInt i=0; i<op->qf->num_output_fields; i++) { 734 if (!strcmp(field_name, (*op->qf->output_fields[i]).field_name)) { 735 qf_field = op->qf->output_fields[i]; 736 op_field = &op->output_fields[i]; 737 goto found; 738 } 739 } 740 // LCOV_EXCL_START 741 return CeedError(op->ceed, CEED_ERROR_INCOMPLETE, 742 "QFunction has no knowledge of field '%s'", 743 field_name); 744 // LCOV_EXCL_STOP 745 found: 746 ierr = CeedOperatorCheckField(op->ceed, qf_field, r, b); CeedChk(ierr); 747 ierr = CeedCalloc(1, op_field); CeedChk(ierr); 748 749 (*op_field)->vec = v; 750 if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) { 751 ierr = CeedVectorReference(v); CeedChk(ierr); 752 } 753 754 (*op_field)->elem_restr = r; 755 ierr = CeedElemRestrictionReference(r); CeedChk(ierr); 756 if (r != CEED_ELEMRESTRICTION_NONE) { 757 op->num_elem = num_elem; 758 op->has_restriction = true; // Restriction set, but num_elem may be 0 759 } 760 761 (*op_field)->basis = b; 762 if (b != CEED_BASIS_COLLOCATED) { 763 if (!op->num_qpts) { 764 ierr = CeedOperatorSetNumQuadraturePoints(op, num_qpts); CeedChk(ierr); 765 } 766 ierr = CeedBasisReference(b); CeedChk(ierr); 767 } 768 769 op->num_fields += 1; 770 size_t len = strlen(field_name); 771 char *tmp; 772 ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr); 773 memcpy(tmp, field_name, len+1); 774 (*op_field)->field_name = tmp; 775 return CEED_ERROR_SUCCESS; 776 } 777 778 /** 779 @brief Get the CeedOperatorFields of a CeedOperator 780 781 Note: Calling this function asserts that setup is complete 782 and sets the CeedOperator as immutable. 783 784 @param op CeedOperator 785 @param[out] input_fields Variable to store input_fields 786 @param[out] output_fields Variable to store output_fields 787 788 @return An error code: 0 - success, otherwise - failure 789 790 @ref Advanced 791 **/ 792 int CeedOperatorGetFields(CeedOperator op, CeedInt *num_input_fields, 793 CeedOperatorField **input_fields, 794 CeedInt *num_output_fields, 795 CeedOperatorField **output_fields) { 796 int ierr; 797 798 if (op->is_composite) 799 // LCOV_EXCL_START 800 return CeedError(op->ceed, CEED_ERROR_MINOR, 801 "Not defined for composite operator"); 802 // LCOV_EXCL_STOP 803 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 804 805 if (num_input_fields) *num_input_fields = op->qf->num_input_fields; 806 if (input_fields) *input_fields = op->input_fields; 807 if (num_output_fields) *num_output_fields = op->qf->num_output_fields; 808 if (output_fields) *output_fields = op->output_fields; 809 return CEED_ERROR_SUCCESS; 810 } 811 812 /** 813 @brief Get the name of a CeedOperatorField 814 815 @param op_field CeedOperatorField 816 @param[out] field_name Variable to store the field name 817 818 @return An error code: 0 - success, otherwise - failure 819 820 @ref Advanced 821 **/ 822 int CeedOperatorFieldGetName(CeedOperatorField op_field, char **field_name) { 823 *field_name = (char *)op_field->field_name; 824 return CEED_ERROR_SUCCESS; 825 } 826 827 /** 828 @brief Get the CeedElemRestriction of a CeedOperatorField 829 830 @param op_field CeedOperatorField 831 @param[out] rstr Variable to store CeedElemRestriction 832 833 @return An error code: 0 - success, otherwise - failure 834 835 @ref Advanced 836 **/ 837 int CeedOperatorFieldGetElemRestriction(CeedOperatorField op_field, 838 CeedElemRestriction *rstr) { 839 *rstr = op_field->elem_restr; 840 return CEED_ERROR_SUCCESS; 841 } 842 843 /** 844 @brief Get the CeedBasis of a CeedOperatorField 845 846 @param op_field CeedOperatorField 847 @param[out] basis Variable to store CeedBasis 848 849 @return An error code: 0 - success, otherwise - failure 850 851 @ref Advanced 852 **/ 853 int CeedOperatorFieldGetBasis(CeedOperatorField op_field, CeedBasis *basis) { 854 *basis = op_field->basis; 855 return CEED_ERROR_SUCCESS; 856 } 857 858 /** 859 @brief Get the CeedVector of a CeedOperatorField 860 861 @param op_field CeedOperatorField 862 @param[out] vec Variable to store CeedVector 863 864 @return An error code: 0 - success, otherwise - failure 865 866 @ref Advanced 867 **/ 868 int CeedOperatorFieldGetVector(CeedOperatorField op_field, CeedVector *vec) { 869 *vec = op_field->vec; 870 return CEED_ERROR_SUCCESS; 871 } 872 873 /** 874 @brief Add a sub-operator to a composite CeedOperator 875 876 @param[out] composite_op Composite CeedOperator 877 @param sub_op Sub-operator CeedOperator 878 879 @return An error code: 0 - success, otherwise - failure 880 881 @ref User 882 */ 883 int CeedCompositeOperatorAddSub(CeedOperator composite_op, 884 CeedOperator sub_op) { 885 int ierr; 886 887 if (!composite_op->is_composite) 888 // LCOV_EXCL_START 889 return CeedError(composite_op->ceed, CEED_ERROR_MINOR, 890 "CeedOperator is not a composite operator"); 891 // LCOV_EXCL_STOP 892 893 if (composite_op->num_suboperators == CEED_COMPOSITE_MAX) 894 // LCOV_EXCL_START 895 return CeedError(composite_op->ceed, CEED_ERROR_UNSUPPORTED, 896 "Cannot add additional sub_operators"); 897 // LCOV_EXCL_STOP 898 if (composite_op->is_immutable) 899 // LCOV_EXCL_START 900 return CeedError(composite_op->ceed, CEED_ERROR_MAJOR, 901 "Operator cannot be changed after set as immutable"); 902 // LCOV_EXCL_STOP 903 904 composite_op->sub_operators[composite_op->num_suboperators] = sub_op; 905 ierr = CeedOperatorReference(sub_op); CeedChk(ierr); 906 composite_op->num_suboperators++; 907 return CEED_ERROR_SUCCESS; 908 } 909 910 /** 911 @brief Set the number of quadrature points associated with a CeedOperator. 912 This should be used when creating a CeedOperator where every 913 field has a collocated basis. This function cannot be used for 914 composite CeedOperators. 915 916 @param op CeedOperator 917 @param num_qpts Number of quadrature points to set 918 919 @return An error code: 0 - success, otherwise - failure 920 921 @ref Advanced 922 **/ 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