1 // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors. 2 // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 3 // 4 // SPDX-License-Identifier: BSD-2-Clause 5 // 6 // This file is part of CEED: http://github.com/ceed 7 8 #include <ceed/ceed.h> 9 #include <ceed/backend.h> 10 #include <ceed-impl.h> 11 #include <stdbool.h> 12 #include <stdio.h> 13 #include <string.h> 14 15 /// @file 16 /// Implementation of CeedOperator interfaces 17 18 /// ---------------------------------------------------------------------------- 19 /// CeedOperator Library Internal Functions 20 /// ---------------------------------------------------------------------------- 21 /// @addtogroup CeedOperatorDeveloper 22 /// @{ 23 24 /** 25 @brief Check if a CeedOperator Field matches the QFunction Field 26 27 @param[in] ceed Ceed object for error handling 28 @param[in] qf_field QFunction Field matching Operator Field 29 @param[in] r Operator Field ElemRestriction 30 @param[in] b Operator Field Basis 31 32 @return An error code: 0 - success, otherwise - failure 33 34 @ref Developer 35 **/ 36 static int CeedOperatorCheckField(Ceed ceed, CeedQFunctionField qf_field, 37 CeedElemRestriction r, CeedBasis b) { 38 int ierr; 39 CeedEvalMode eval_mode = qf_field->eval_mode; 40 CeedInt dim = 1, num_comp = 1, restr_num_comp = 1, size = qf_field->size; 41 // Restriction 42 if (r != CEED_ELEMRESTRICTION_NONE) { 43 if (eval_mode == CEED_EVAL_WEIGHT) { 44 // LCOV_EXCL_START 45 return CeedError(ceed, CEED_ERROR_INCOMPATIBLE, 46 "CEED_ELEMRESTRICTION_NONE should be used " 47 "for a field with eval mode CEED_EVAL_WEIGHT"); 48 // LCOV_EXCL_STOP 49 } 50 ierr = CeedElemRestrictionGetNumComponents(r, &restr_num_comp); 51 CeedChk(ierr); 52 } 53 if ((r == CEED_ELEMRESTRICTION_NONE) != (eval_mode == CEED_EVAL_WEIGHT)) { 54 // LCOV_EXCL_START 55 return CeedError(ceed, CEED_ERROR_INCOMPATIBLE, 56 "CEED_ELEMRESTRICTION_NONE and CEED_EVAL_WEIGHT " 57 "must be used together."); 58 // LCOV_EXCL_STOP 59 } 60 // Basis 61 if (b != CEED_BASIS_COLLOCATED) { 62 if (eval_mode == CEED_EVAL_NONE) 63 // LCOV_EXCL_START 64 return CeedError(ceed, CEED_ERROR_INCOMPATIBLE, 65 "Field '%s' configured with CEED_EVAL_NONE must " 66 "be used with CEED_BASIS_COLLOCATED", 67 // LCOV_EXCL_STOP 68 qf_field->field_name); 69 ierr = CeedBasisGetDimension(b, &dim); CeedChk(ierr); 70 ierr = CeedBasisGetNumComponents(b, &num_comp); CeedChk(ierr); 71 if (r != CEED_ELEMRESTRICTION_NONE && restr_num_comp != num_comp) { 72 // LCOV_EXCL_START 73 return CeedError(ceed, CEED_ERROR_DIMENSION, 74 "Field '%s' of size %" CeedInt_FMT " and EvalMode %s: ElemRestriction " 75 "has %" CeedInt_FMT " components, but Basis has %" CeedInt_FMT " components", 76 qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], 77 restr_num_comp, 78 num_comp); 79 // LCOV_EXCL_STOP 80 } 81 } 82 // Field size 83 switch(eval_mode) { 84 case CEED_EVAL_NONE: 85 if (size != restr_num_comp) 86 // LCOV_EXCL_START 87 return CeedError(ceed, CEED_ERROR_DIMENSION, 88 "Field '%s' of size %" CeedInt_FMT " and EvalMode %s: ElemRestriction has " 89 CeedInt_FMT " components", 90 qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], 91 restr_num_comp); 92 // LCOV_EXCL_STOP 93 break; 94 case CEED_EVAL_INTERP: 95 if (size != num_comp) 96 // LCOV_EXCL_START 97 return CeedError(ceed, CEED_ERROR_DIMENSION, 98 "Field '%s' of size %" CeedInt_FMT 99 " and EvalMode %s: ElemRestriction/Basis has " 100 CeedInt_FMT " components", 101 qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], 102 num_comp); 103 // LCOV_EXCL_STOP 104 break; 105 case CEED_EVAL_GRAD: 106 if (size != num_comp * dim) 107 // LCOV_EXCL_START 108 return CeedError(ceed, CEED_ERROR_DIMENSION, 109 "Field '%s' of size %" CeedInt_FMT " and EvalMode %s in %" CeedInt_FMT 110 " dimensions: " 111 "ElemRestriction/Basis has %" CeedInt_FMT " components", 112 qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], dim, 113 num_comp); 114 // LCOV_EXCL_STOP 115 break; 116 case CEED_EVAL_WEIGHT: 117 // No additional checks required 118 break; 119 case CEED_EVAL_DIV: 120 // Not implemented 121 break; 122 case CEED_EVAL_CURL: 123 // Not implemented 124 break; 125 } 126 return CEED_ERROR_SUCCESS; 127 } 128 129 /** 130 @brief View a field of a CeedOperator 131 132 @param[in] field Operator field to view 133 @param[in] qf_field QFunction field (carries field name) 134 @param[in] field_number Number of field being viewed 135 @param[in] sub true indicates sub-operator, which increases indentation; false for top-level operator 136 @param[in] input true for an input field; false for output field 137 @param[in] stream Stream to view to, e.g., stdout 138 139 @return An error code: 0 - success, otherwise - failure 140 141 @ref Utility 142 **/ 143 static int CeedOperatorFieldView(CeedOperatorField field, 144 CeedQFunctionField qf_field, 145 CeedInt field_number, bool sub, bool input, 146 FILE *stream) { 147 const char *pre = sub ? " " : ""; 148 const char *in_out = input ? "Input" : "Output"; 149 150 fprintf(stream, "%s %s field %" CeedInt_FMT ":\n" 151 "%s Name: \"%s\"\n", 152 pre, in_out, field_number, pre, qf_field->field_name); 153 154 fprintf(stream, "%s Size: %" CeedInt_FMT "\n", pre, qf_field->size); 155 156 fprintf(stream, "%s EvalMode: %s\n", pre, 157 CeedEvalModes[qf_field->eval_mode]); 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 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 num_elem, num_qpts; 186 ierr = CeedOperatorGetNumElements(op, &num_elem); CeedChk(ierr); 187 ierr = CeedOperatorGetNumQuadraturePoints(op, &num_qpts); CeedChk(ierr); 188 189 CeedInt total_fields = 0; 190 ierr = CeedOperatorGetNumArgs(op, &total_fields); CeedChk(ierr); 191 fprintf(stream, "%s %" CeedInt_FMT " elements with %" CeedInt_FMT 192 " quadrature points each\n", 193 pre, num_elem, num_qpts); 194 195 fprintf(stream, "%s %" CeedInt_FMT " field%s\n", pre, total_fields, 196 total_fields>1 ? "s" : ""); 197 198 fprintf(stream, "%s %" CeedInt_FMT " input field%s:\n", pre, 199 op->qf->num_input_fields, 200 op->qf->num_input_fields>1 ? "s" : ""); 201 for (CeedInt i=0; i<op->qf->num_input_fields; i++) { 202 ierr = CeedOperatorFieldView(op->input_fields[i], op->qf->input_fields[i], 203 i, sub, 1, stream); CeedChk(ierr); 204 } 205 206 fprintf(stream, "%s %" CeedInt_FMT " output field%s:\n", pre, 207 op->qf->num_output_fields, 208 op->qf->num_output_fields>1 ? "s" : ""); 209 for (CeedInt i=0; i<op->qf->num_output_fields; i++) { 210 ierr = CeedOperatorFieldView(op->output_fields[i], op->qf->output_fields[i], 211 i, sub, 0, stream); CeedChk(ierr); 212 } 213 return CEED_ERROR_SUCCESS; 214 } 215 216 /** 217 @brief Find the active vector basis for a non-composite CeedOperator 218 219 @param[in] op CeedOperator to find active basis for 220 @param[out] active_basis Basis for active input vector or NULL for composite operator 221 222 @return An error code: 0 - success, otherwise - failure 223 224 @ ref Developer 225 **/ 226 int CeedOperatorGetActiveBasis(CeedOperator op, CeedBasis *active_basis) { 227 *active_basis = NULL; 228 if (op->is_composite) return CEED_ERROR_SUCCESS; 229 for (CeedInt i = 0; i < op->qf->num_input_fields; i++) 230 if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) { 231 *active_basis = op->input_fields[i]->basis; 232 break; 233 } 234 235 if (!*active_basis) { 236 // LCOV_EXCL_START 237 int ierr; 238 Ceed ceed; 239 ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); 240 return CeedError(ceed, CEED_ERROR_MINOR, 241 "No active CeedBasis found"); 242 // LCOV_EXCL_STOP 243 } 244 return CEED_ERROR_SUCCESS; 245 } 246 247 /** 248 @brief Find the active vector ElemRestriction for a non-composite CeedOperator 249 250 @param[in] op CeedOperator to find active basis for 251 @param[out] active_rstr ElemRestriction for active input vector or NULL for composite operator 252 253 @return An error code: 0 - success, otherwise - failure 254 255 @ref Utility 256 **/ 257 int CeedOperatorGetActiveElemRestriction(CeedOperator op, 258 CeedElemRestriction *active_rstr) { 259 *active_rstr = NULL; 260 if (op->is_composite) return CEED_ERROR_SUCCESS; 261 for (CeedInt i = 0; i < op->qf->num_input_fields; i++) 262 if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) { 263 *active_rstr = op->input_fields[i]->elem_restr; 264 break; 265 } 266 267 if (!*active_rstr) { 268 // LCOV_EXCL_START 269 int ierr; 270 Ceed ceed; 271 ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); 272 return CeedError(ceed, CEED_ERROR_INCOMPLETE, 273 "No active CeedElemRestriction found"); 274 // LCOV_EXCL_STOP 275 } 276 return CEED_ERROR_SUCCESS; 277 } 278 279 /** 280 @brief Set QFunctionContext field value of the specified type. 281 For composite operators, the value is set in all 282 sub-operator QFunctionContexts that have a matching `field_name`. 283 A non-zero error code is returned for single operators 284 that do not have a matching field of the same type or composite 285 operators that do not have any field of a matching type. 286 287 @param op CeedOperator 288 @param field_label Label of field to set 289 @param field_type Type of field to set 290 @param value Value to set 291 292 @return An error code: 0 - success, otherwise - failure 293 294 @ref User 295 **/ 296 static int CeedOperatorContextSetGeneric(CeedOperator op, 297 CeedContextFieldLabel field_label, CeedContextFieldType field_type, 298 void *value) { 299 int ierr; 300 301 if (!field_label) 302 // LCOV_EXCL_START 303 return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, 304 "Invalid field label"); 305 // LCOV_EXCL_STOP 306 307 bool is_composite = false; 308 ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 309 if (is_composite) { 310 CeedInt num_sub; 311 CeedOperator *sub_operators; 312 313 ierr = CeedOperatorGetNumSub(op, &num_sub); CeedChk(ierr); 314 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 315 if (num_sub != field_label->num_sub_labels) 316 // LCOV_EXCL_START 317 return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, 318 "ContextLabel does not correspond to composite operator.\n" 319 "Use CeedOperatorGetContextFieldLabel()."); 320 // LCOV_EXCL_STOP 321 322 for (CeedInt i = 0; i < num_sub; i++) { 323 // Try every sub-operator, ok if some sub-operators do not have field 324 if (field_label->sub_labels[i] && sub_operators[i]->qf->ctx) { 325 ierr = CeedQFunctionContextSetGeneric(sub_operators[i]->qf->ctx, 326 field_label->sub_labels[i], 327 field_type, value); CeedChk(ierr); 328 } 329 } 330 } else { 331 if (!op->qf->ctx) 332 // LCOV_EXCL_START 333 return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, 334 "QFunction does not have context data"); 335 // LCOV_EXCL_STOP 336 337 ierr = CeedQFunctionContextSetGeneric(op->qf->ctx, field_label, 338 field_type, value); CeedChk(ierr); 339 } 340 341 return CEED_ERROR_SUCCESS; 342 } 343 344 /// @} 345 346 /// ---------------------------------------------------------------------------- 347 /// CeedOperator Backend API 348 /// ---------------------------------------------------------------------------- 349 /// @addtogroup CeedOperatorBackend 350 /// @{ 351 352 /** 353 @brief Get the number of arguments associated with a CeedOperator 354 355 @param op CeedOperator 356 @param[out] num_args Variable to store vector number of arguments 357 358 @return An error code: 0 - success, otherwise - failure 359 360 @ref Backend 361 **/ 362 363 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *num_args) { 364 if (op->is_composite) 365 // LCOV_EXCL_START 366 return CeedError(op->ceed, CEED_ERROR_MINOR, 367 "Not defined for composite operators"); 368 // LCOV_EXCL_STOP 369 370 *num_args = op->num_fields; 371 return CEED_ERROR_SUCCESS; 372 } 373 374 /** 375 @brief Get the setup status of a CeedOperator 376 377 @param op CeedOperator 378 @param[out] is_setup_done Variable to store setup status 379 380 @return An error code: 0 - success, otherwise - failure 381 382 @ref Backend 383 **/ 384 385 int CeedOperatorIsSetupDone(CeedOperator op, bool *is_setup_done) { 386 *is_setup_done = op->is_backend_setup; 387 return CEED_ERROR_SUCCESS; 388 } 389 390 /** 391 @brief Get the QFunction associated with a CeedOperator 392 393 @param op CeedOperator 394 @param[out] qf Variable to store QFunction 395 396 @return An error code: 0 - success, otherwise - failure 397 398 @ref Backend 399 **/ 400 401 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) { 402 if (op->is_composite) 403 // LCOV_EXCL_START 404 return CeedError(op->ceed, CEED_ERROR_MINOR, 405 "Not defined for composite operator"); 406 // LCOV_EXCL_STOP 407 408 *qf = op->qf; 409 return CEED_ERROR_SUCCESS; 410 } 411 412 /** 413 @brief Get a boolean value indicating if the CeedOperator is composite 414 415 @param op CeedOperator 416 @param[out] is_composite Variable to store composite status 417 418 @return An error code: 0 - success, otherwise - failure 419 420 @ref Backend 421 **/ 422 423 int CeedOperatorIsComposite(CeedOperator op, bool *is_composite) { 424 *is_composite = op->is_composite; 425 return CEED_ERROR_SUCCESS; 426 } 427 428 /** 429 @brief Get the number of sub_operators associated with a CeedOperator 430 431 @param op CeedOperator 432 @param[out] num_suboperators Variable to store number of sub_operators 433 434 @return An error code: 0 - success, otherwise - failure 435 436 @ref Backend 437 **/ 438 439 int CeedOperatorGetNumSub(CeedOperator op, CeedInt *num_suboperators) { 440 if (!op->is_composite) 441 // LCOV_EXCL_START 442 return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator"); 443 // LCOV_EXCL_STOP 444 445 *num_suboperators = op->num_suboperators; 446 return CEED_ERROR_SUCCESS; 447 } 448 449 /** 450 @brief Get the list of sub_operators associated with a CeedOperator 451 452 @param op CeedOperator 453 @param[out] sub_operators Variable to store list of sub_operators 454 455 @return An error code: 0 - success, otherwise - failure 456 457 @ref Backend 458 **/ 459 460 int CeedOperatorGetSubList(CeedOperator op, CeedOperator **sub_operators) { 461 if (!op->is_composite) 462 // LCOV_EXCL_START 463 return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator"); 464 // LCOV_EXCL_STOP 465 466 *sub_operators = op->sub_operators; 467 return CEED_ERROR_SUCCESS; 468 } 469 470 /** 471 @brief Get the backend data of a CeedOperator 472 473 @param op CeedOperator 474 @param[out] data Variable to store data 475 476 @return An error code: 0 - success, otherwise - failure 477 478 @ref Backend 479 **/ 480 481 int CeedOperatorGetData(CeedOperator op, void *data) { 482 *(void **)data = op->data; 483 return CEED_ERROR_SUCCESS; 484 } 485 486 /** 487 @brief Set the backend data of a CeedOperator 488 489 @param[out] op CeedOperator 490 @param data Data to set 491 492 @return An error code: 0 - success, otherwise - failure 493 494 @ref Backend 495 **/ 496 497 int CeedOperatorSetData(CeedOperator op, void *data) { 498 op->data = data; 499 return CEED_ERROR_SUCCESS; 500 } 501 502 /** 503 @brief Increment the reference counter for a CeedOperator 504 505 @param op CeedOperator to increment the reference counter 506 507 @return An error code: 0 - success, otherwise - failure 508 509 @ref Backend 510 **/ 511 int CeedOperatorReference(CeedOperator op) { 512 op->ref_count++; 513 return CEED_ERROR_SUCCESS; 514 } 515 516 /** 517 @brief Set the setup flag of a CeedOperator to True 518 519 @param op CeedOperator 520 521 @return An error code: 0 - success, otherwise - failure 522 523 @ref Backend 524 **/ 525 526 int CeedOperatorSetSetupDone(CeedOperator op) { 527 op->is_backend_setup = true; 528 return CEED_ERROR_SUCCESS; 529 } 530 531 /// @} 532 533 /// ---------------------------------------------------------------------------- 534 /// CeedOperator Public API 535 /// ---------------------------------------------------------------------------- 536 /// @addtogroup CeedOperatorUser 537 /// @{ 538 539 /** 540 @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and 541 CeedElemRestriction can be associated with CeedQFunction fields with 542 \ref CeedOperatorSetField. 543 544 @param ceed A Ceed object where the CeedOperator will be created 545 @param qf QFunction defining the action of the operator at quadrature points 546 @param dqf QFunction defining the action of the Jacobian of @a qf (or 547 @ref CEED_QFUNCTION_NONE) 548 @param dqfT QFunction defining the action of the transpose of the Jacobian 549 of @a qf (or @ref CEED_QFUNCTION_NONE) 550 @param[out] op Address of the variable where the newly created 551 CeedOperator will be stored 552 553 @return An error code: 0 - success, otherwise - failure 554 555 @ref User 556 */ 557 int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, 558 CeedQFunction dqfT, CeedOperator *op) { 559 int ierr; 560 561 if (!ceed->OperatorCreate) { 562 Ceed delegate; 563 ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr); 564 565 if (!delegate) 566 // LCOV_EXCL_START 567 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 568 "Backend does not support OperatorCreate"); 569 // LCOV_EXCL_STOP 570 571 ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr); 572 return CEED_ERROR_SUCCESS; 573 } 574 575 if (!qf || qf == CEED_QFUNCTION_NONE) 576 // LCOV_EXCL_START 577 return CeedError(ceed, CEED_ERROR_MINOR, 578 "Operator must have a valid QFunction."); 579 // LCOV_EXCL_STOP 580 ierr = CeedCalloc(1, op); CeedChk(ierr); 581 (*op)->ceed = ceed; 582 ierr = CeedReference(ceed); CeedChk(ierr); 583 (*op)->ref_count = 1; 584 (*op)->qf = qf; 585 (*op)->input_size = -1; 586 (*op)->output_size = -1; 587 ierr = CeedQFunctionReference(qf); CeedChk(ierr); 588 if (dqf && dqf != CEED_QFUNCTION_NONE) { 589 (*op)->dqf = dqf; 590 ierr = CeedQFunctionReference(dqf); CeedChk(ierr); 591 } 592 if (dqfT && dqfT != CEED_QFUNCTION_NONE) { 593 (*op)->dqfT = dqfT; 594 ierr = CeedQFunctionReference(dqfT); CeedChk(ierr); 595 } 596 ierr = CeedQFunctionAssemblyDataCreate(ceed, &(*op)->qf_assembled); 597 CeedChk(ierr); 598 ierr = CeedCalloc(CEED_FIELD_MAX, &(*op)->input_fields); CeedChk(ierr); 599 ierr = CeedCalloc(CEED_FIELD_MAX, &(*op)->output_fields); CeedChk(ierr); 600 ierr = ceed->OperatorCreate(*op); CeedChk(ierr); 601 return CEED_ERROR_SUCCESS; 602 } 603 604 /** 605 @brief Create an operator that composes the action of several operators 606 607 @param ceed A Ceed object where the CeedOperator will be created 608 @param[out] op Address of the variable where the newly created 609 Composite CeedOperator will be stored 610 611 @return An error code: 0 - success, otherwise - failure 612 613 @ref User 614 */ 615 int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) { 616 int ierr; 617 618 if (!ceed->CompositeOperatorCreate) { 619 Ceed delegate; 620 ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr); 621 622 if (delegate) { 623 ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr); 624 return CEED_ERROR_SUCCESS; 625 } 626 } 627 628 ierr = CeedCalloc(1, op); CeedChk(ierr); 629 (*op)->ceed = ceed; 630 ierr = CeedReference(ceed); CeedChk(ierr); 631 (*op)->is_composite = true; 632 ierr = CeedCalloc(CEED_COMPOSITE_MAX, &(*op)->sub_operators); CeedChk(ierr); 633 (*op)->input_size = -1; 634 (*op)->output_size = -1; 635 636 if (ceed->CompositeOperatorCreate) { 637 ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr); 638 } 639 return CEED_ERROR_SUCCESS; 640 } 641 642 /** 643 @brief Copy the pointer to a CeedOperator. Both pointers should 644 be destroyed with `CeedOperatorDestroy()`; 645 Note: If `*op_copy` is non-NULL, then it is assumed that 646 `*op_copy` is a pointer to a CeedOperator. This 647 CeedOperator will be destroyed if `*op_copy` is the only 648 reference to this CeedOperator. 649 650 @param op CeedOperator to copy reference to 651 @param[out] op_copy Variable to store copied reference 652 653 @return An error code: 0 - success, otherwise - failure 654 655 @ref User 656 **/ 657 int CeedOperatorReferenceCopy(CeedOperator op, CeedOperator *op_copy) { 658 int ierr; 659 660 ierr = CeedOperatorReference(op); CeedChk(ierr); 661 ierr = CeedOperatorDestroy(op_copy); CeedChk(ierr); 662 *op_copy = op; 663 return CEED_ERROR_SUCCESS; 664 } 665 666 /** 667 @brief Provide a field to a CeedOperator for use by its CeedQFunction 668 669 This function is used to specify both active and passive fields to a 670 CeedOperator. For passive fields, a vector @arg v must be provided. Passive 671 fields can inputs or outputs (updated in-place when operator is applied). 672 673 Active fields must be specified using this function, but their data (in a 674 CeedVector) is passed in CeedOperatorApply(). There can be at most one active 675 input CeedVector and at most one active output CeedVector passed to 676 CeedOperatorApply(). 677 678 @param op CeedOperator on which to provide the field 679 @param field_name Name of the field (to be matched with the name used by 680 CeedQFunction) 681 @param r CeedElemRestriction 682 @param b CeedBasis in which the field resides or @ref CEED_BASIS_COLLOCATED 683 if collocated with quadrature points 684 @param v CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE 685 if field is active or @ref CEED_VECTOR_NONE if using 686 @ref CEED_EVAL_WEIGHT in the QFunction 687 688 @return An error code: 0 - success, otherwise - failure 689 690 @ref User 691 **/ 692 int CeedOperatorSetField(CeedOperator op, const char *field_name, 693 CeedElemRestriction r, CeedBasis b, CeedVector v) { 694 int ierr; 695 if (op->is_composite) 696 // LCOV_EXCL_START 697 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 698 "Cannot add field to composite operator."); 699 // LCOV_EXCL_STOP 700 if (op->is_immutable) 701 // LCOV_EXCL_START 702 return CeedError(op->ceed, CEED_ERROR_MAJOR, 703 "Operator cannot be changed after set as immutable"); 704 // LCOV_EXCL_STOP 705 if (!r) 706 // LCOV_EXCL_START 707 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 708 "ElemRestriction r for field \"%s\" must be non-NULL.", 709 field_name); 710 // LCOV_EXCL_STOP 711 if (!b) 712 // LCOV_EXCL_START 713 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 714 "Basis b for field \"%s\" must be non-NULL.", 715 field_name); 716 // LCOV_EXCL_STOP 717 if (!v) 718 // LCOV_EXCL_START 719 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 720 "Vector v for field \"%s\" must be non-NULL.", 721 field_name); 722 // LCOV_EXCL_STOP 723 724 CeedInt num_elem; 725 ierr = CeedElemRestrictionGetNumElements(r, &num_elem); CeedChk(ierr); 726 if (r != CEED_ELEMRESTRICTION_NONE && op->has_restriction && 727 op->num_elem != num_elem) 728 // LCOV_EXCL_START 729 return CeedError(op->ceed, CEED_ERROR_DIMENSION, 730 "ElemRestriction with %" CeedInt_FMT " elements incompatible with prior " 731 CeedInt_FMT " elements", num_elem, op->num_elem); 732 // LCOV_EXCL_STOP 733 734 CeedInt num_qpts = 0; 735 if (b != CEED_BASIS_COLLOCATED) { 736 ierr = CeedBasisGetNumQuadraturePoints(b, &num_qpts); CeedChk(ierr); 737 if (op->num_qpts && op->num_qpts != num_qpts) 738 // LCOV_EXCL_START 739 return CeedError(op->ceed, CEED_ERROR_DIMENSION, 740 "Basis with %" CeedInt_FMT " quadrature points " 741 "incompatible with prior %" CeedInt_FMT " points", num_qpts, 742 op->num_qpts); 743 // LCOV_EXCL_STOP 744 } 745 CeedQFunctionField qf_field; 746 CeedOperatorField *op_field; 747 bool is_input = true; 748 for (CeedInt i=0; i<op->qf->num_input_fields; i++) { 749 if (!strcmp(field_name, (*op->qf->input_fields[i]).field_name)) { 750 qf_field = op->qf->input_fields[i]; 751 op_field = &op->input_fields[i]; 752 goto found; 753 } 754 } 755 is_input = false; 756 for (CeedInt i=0; i<op->qf->num_output_fields; i++) { 757 if (!strcmp(field_name, (*op->qf->output_fields[i]).field_name)) { 758 qf_field = op->qf->output_fields[i]; 759 op_field = &op->output_fields[i]; 760 goto found; 761 } 762 } 763 // LCOV_EXCL_START 764 return CeedError(op->ceed, CEED_ERROR_INCOMPLETE, 765 "QFunction has no knowledge of field '%s'", 766 field_name); 767 // LCOV_EXCL_STOP 768 found: 769 ierr = CeedOperatorCheckField(op->ceed, qf_field, r, b); CeedChk(ierr); 770 ierr = CeedCalloc(1, op_field); CeedChk(ierr); 771 772 if (v == CEED_VECTOR_ACTIVE) { 773 CeedSize l_size; 774 ierr = CeedElemRestrictionGetLVectorSize(r, &l_size); CeedChk(ierr); 775 if (is_input) { 776 if (op->input_size == -1) op->input_size = l_size; 777 if (l_size != op->input_size) 778 // LCOV_EXCL_START 779 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 780 "LVector size %td does not match previous size %td", 781 l_size, op->input_size); 782 // LCOV_EXCL_STOP 783 } else { 784 if (op->output_size == -1) op->output_size = l_size; 785 if (l_size != op->output_size) 786 // LCOV_EXCL_START 787 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 788 "LVector size %td does not match previous size %td", 789 l_size, op->output_size); 790 // LCOV_EXCL_STOP 791 } 792 } 793 794 (*op_field)->vec = v; 795 if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) { 796 ierr = CeedVectorReference(v); CeedChk(ierr); 797 } 798 799 (*op_field)->elem_restr = r; 800 ierr = CeedElemRestrictionReference(r); CeedChk(ierr); 801 if (r != CEED_ELEMRESTRICTION_NONE) { 802 op->num_elem = num_elem; 803 op->has_restriction = true; // Restriction set, but num_elem may be 0 804 } 805 806 (*op_field)->basis = b; 807 if (b != CEED_BASIS_COLLOCATED) { 808 if (!op->num_qpts) { 809 ierr = CeedOperatorSetNumQuadraturePoints(op, num_qpts); CeedChk(ierr); 810 } 811 ierr = CeedBasisReference(b); CeedChk(ierr); 812 } 813 814 op->num_fields += 1; 815 ierr = CeedStringAllocCopy(field_name, (char **)&(*op_field)->field_name); 816 CeedChk(ierr); 817 return CEED_ERROR_SUCCESS; 818 } 819 820 /** 821 @brief Get the CeedOperatorFields of a CeedOperator 822 823 Note: Calling this function asserts that setup is complete 824 and sets the CeedOperator as immutable. 825 826 @param op CeedOperator 827 @param[out] num_input_fields Variable to store number of input fields 828 @param[out] input_fields Variable to store input_fields 829 @param[out] num_output_fields Variable to store number of output fields 830 @param[out] output_fields Variable to store output_fields 831 832 @return An error code: 0 - success, otherwise - failure 833 834 @ref Advanced 835 **/ 836 int CeedOperatorGetFields(CeedOperator op, CeedInt *num_input_fields, 837 CeedOperatorField **input_fields, 838 CeedInt *num_output_fields, 839 CeedOperatorField **output_fields) { 840 int ierr; 841 842 if (op->is_composite) 843 // LCOV_EXCL_START 844 return CeedError(op->ceed, CEED_ERROR_MINOR, 845 "Not defined for composite operator"); 846 // LCOV_EXCL_STOP 847 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 848 849 if (num_input_fields) *num_input_fields = op->qf->num_input_fields; 850 if (input_fields) *input_fields = op->input_fields; 851 if (num_output_fields) *num_output_fields = op->qf->num_output_fields; 852 if (output_fields) *output_fields = op->output_fields; 853 return CEED_ERROR_SUCCESS; 854 } 855 856 /** 857 @brief Get the name of a CeedOperatorField 858 859 @param op_field CeedOperatorField 860 @param[out] field_name Variable to store the field name 861 862 @return An error code: 0 - success, otherwise - failure 863 864 @ref Advanced 865 **/ 866 int CeedOperatorFieldGetName(CeedOperatorField op_field, char **field_name) { 867 *field_name = (char *)op_field->field_name; 868 return CEED_ERROR_SUCCESS; 869 } 870 871 /** 872 @brief Get the CeedElemRestriction of a CeedOperatorField 873 874 @param op_field CeedOperatorField 875 @param[out] rstr Variable to store CeedElemRestriction 876 877 @return An error code: 0 - success, otherwise - failure 878 879 @ref Advanced 880 **/ 881 int CeedOperatorFieldGetElemRestriction(CeedOperatorField op_field, 882 CeedElemRestriction *rstr) { 883 *rstr = op_field->elem_restr; 884 return CEED_ERROR_SUCCESS; 885 } 886 887 /** 888 @brief Get the CeedBasis of a CeedOperatorField 889 890 @param op_field CeedOperatorField 891 @param[out] basis Variable to store CeedBasis 892 893 @return An error code: 0 - success, otherwise - failure 894 895 @ref Advanced 896 **/ 897 int CeedOperatorFieldGetBasis(CeedOperatorField op_field, CeedBasis *basis) { 898 *basis = op_field->basis; 899 return CEED_ERROR_SUCCESS; 900 } 901 902 /** 903 @brief Get the CeedVector of a CeedOperatorField 904 905 @param op_field CeedOperatorField 906 @param[out] vec Variable to store CeedVector 907 908 @return An error code: 0 - success, otherwise - failure 909 910 @ref Advanced 911 **/ 912 int CeedOperatorFieldGetVector(CeedOperatorField op_field, CeedVector *vec) { 913 *vec = op_field->vec; 914 return CEED_ERROR_SUCCESS; 915 } 916 917 /** 918 @brief Add a sub-operator to a composite CeedOperator 919 920 @param[out] composite_op Composite CeedOperator 921 @param sub_op Sub-operator CeedOperator 922 923 @return An error code: 0 - success, otherwise - failure 924 925 @ref User 926 */ 927 int CeedCompositeOperatorAddSub(CeedOperator composite_op, 928 CeedOperator sub_op) { 929 int ierr; 930 931 if (!composite_op->is_composite) 932 // LCOV_EXCL_START 933 return CeedError(composite_op->ceed, CEED_ERROR_MINOR, 934 "CeedOperator is not a composite operator"); 935 // LCOV_EXCL_STOP 936 937 if (composite_op->num_suboperators == CEED_COMPOSITE_MAX) 938 // LCOV_EXCL_START 939 return CeedError(composite_op->ceed, CEED_ERROR_UNSUPPORTED, 940 "Cannot add additional sub-operators"); 941 // LCOV_EXCL_STOP 942 if (composite_op->is_immutable) 943 // LCOV_EXCL_START 944 return CeedError(composite_op->ceed, CEED_ERROR_MAJOR, 945 "Operator cannot be changed after set as immutable"); 946 // LCOV_EXCL_STOP 947 948 { 949 CeedSize input_size, output_size; 950 ierr = CeedOperatorGetActiveVectorLengths(sub_op, &input_size, &output_size); 951 CeedChk(ierr); 952 if (composite_op->input_size == -1) composite_op->input_size = input_size; 953 if (composite_op->output_size == -1) composite_op->output_size = output_size; 954 // Note, a size of -1 means no active vector restriction set, so no incompatibility 955 if ((input_size != -1 && input_size != composite_op->input_size) || 956 (output_size != -1 && output_size != composite_op->output_size)) 957 // LCOV_EXCL_START 958 return CeedError(composite_op->ceed, CEED_ERROR_MAJOR, 959 "Sub-operators must have compatible dimensions; " 960 "composite operator of shape (%td, %td) not compatible with " 961 "sub-operator of shape (%td, %td)", 962 composite_op->input_size, composite_op->output_size, input_size, output_size); 963 // LCOV_EXCL_STOP 964 } 965 966 composite_op->sub_operators[composite_op->num_suboperators] = sub_op; 967 ierr = CeedOperatorReference(sub_op); CeedChk(ierr); 968 composite_op->num_suboperators++; 969 return CEED_ERROR_SUCCESS; 970 } 971 972 /** 973 @brief Check if a CeedOperator is ready to be used. 974 975 @param[in] op CeedOperator to check 976 977 @return An error code: 0 - success, otherwise - failure 978 979 @ref User 980 **/ 981 int CeedOperatorCheckReady(CeedOperator op) { 982 int ierr; 983 Ceed ceed; 984 ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); 985 986 if (op->is_interface_setup) 987 return CEED_ERROR_SUCCESS; 988 989 CeedQFunction qf = op->qf; 990 if (op->is_composite) { 991 if (!op->num_suboperators) 992 // LCOV_EXCL_START 993 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No sub_operators set"); 994 // LCOV_EXCL_STOP 995 for (CeedInt i = 0; i < op->num_suboperators; i++) { 996 ierr = CeedOperatorCheckReady(op->sub_operators[i]); CeedChk(ierr); 997 } 998 // Sub-operators could be modified after adding to composite operator 999 // Need to verify no lvec incompatibility from any changes 1000 CeedSize input_size, output_size; 1001 ierr = CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size); 1002 CeedChk(ierr); 1003 } else { 1004 if (op->num_fields == 0) 1005 // LCOV_EXCL_START 1006 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No operator fields set"); 1007 // LCOV_EXCL_STOP 1008 if (op->num_fields < qf->num_input_fields + qf->num_output_fields) 1009 // LCOV_EXCL_START 1010 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set"); 1011 // LCOV_EXCL_STOP 1012 if (!op->has_restriction) 1013 // LCOV_EXCL_START 1014 return CeedError(ceed, CEED_ERROR_INCOMPLETE, 1015 "At least one restriction required"); 1016 // LCOV_EXCL_STOP 1017 if (op->num_qpts == 0) 1018 // LCOV_EXCL_START 1019 return CeedError(ceed, CEED_ERROR_INCOMPLETE, 1020 "At least one non-collocated basis is required " 1021 "or the number of quadrature points must be set"); 1022 // LCOV_EXCL_STOP 1023 } 1024 1025 // Flag as immutable and ready 1026 op->is_interface_setup = true; 1027 if (op->qf && op->qf != CEED_QFUNCTION_NONE) 1028 // LCOV_EXCL_START 1029 op->qf->is_immutable = true; 1030 // LCOV_EXCL_STOP 1031 if (op->dqf && op->dqf != CEED_QFUNCTION_NONE) 1032 // LCOV_EXCL_START 1033 op->dqf->is_immutable = true; 1034 // LCOV_EXCL_STOP 1035 if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE) 1036 // LCOV_EXCL_START 1037 op->dqfT->is_immutable = true; 1038 // LCOV_EXCL_STOP 1039 return CEED_ERROR_SUCCESS; 1040 } 1041 1042 /** 1043 @brief Get vector lengths for the active input and/or output vectors of a CeedOperator. 1044 Note: Lengths of -1 indicate that the CeedOperator does not have an 1045 active input and/or output. 1046 1047 @param[in] op CeedOperator 1048 @param[out] input_size Variable to store active input vector length, or NULL 1049 @param[out] output_size Variable to store active output vector length, or NULL 1050 1051 @return An error code: 0 - success, otherwise - failure 1052 1053 @ref User 1054 **/ 1055 int CeedOperatorGetActiveVectorLengths(CeedOperator op, CeedSize *input_size, 1056 CeedSize *output_size) { 1057 int ierr; 1058 bool is_composite; 1059 1060 if (input_size) *input_size = op->input_size; 1061 if (output_size) *output_size = op->output_size; 1062 1063 ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1064 if (is_composite && (op->input_size == -1 || op->output_size == -1)) { 1065 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1066 CeedSize sub_input_size, sub_output_size; 1067 ierr = CeedOperatorGetActiveVectorLengths(op->sub_operators[i], 1068 &sub_input_size, &sub_output_size); CeedChk(ierr); 1069 if (op->input_size == -1) op->input_size = sub_input_size; 1070 if (op->output_size == -1) op->output_size = sub_output_size; 1071 // Note, a size of -1 means no active vector restriction set, so no incompatibility 1072 if ((sub_input_size != -1 && sub_input_size != op->input_size) || 1073 (sub_output_size != -1 && sub_output_size != op->output_size)) 1074 // LCOV_EXCL_START 1075 return CeedError(op->ceed, CEED_ERROR_MAJOR, 1076 "Sub-operators must have compatible dimensions; " 1077 "composite operator of shape (%td, %td) not compatible with " 1078 "sub-operator of shape (%td, %td)", 1079 op->input_size, op->output_size, input_size, output_size); 1080 // LCOV_EXCL_STOP 1081 } 1082 } 1083 1084 return CEED_ERROR_SUCCESS; 1085 } 1086 1087 /** 1088 @brief Set reuse of CeedQFunction data in CeedOperatorLinearAssemble* functions. 1089 When `reuse_assembly_data = false` (default), the CeedQFunction associated 1090 with this CeedOperator is re-assembled every time a `CeedOperatorLinearAssemble*` 1091 function is called. 1092 When `reuse_assembly_data = true`, the CeedQFunction associated with 1093 this CeedOperator is reused between calls to 1094 `CeedOperatorSetQFunctionAssemblyDataUpdated`. 1095 1096 @param[in] op CeedOperator 1097 @param[in] reuse_assembly_data Boolean flag setting assembly data reuse 1098 1099 @return An error code: 0 - success, otherwise - failure 1100 1101 @ref Advanced 1102 **/ 1103 int CeedOperatorSetQFunctionAssemblyReuse(CeedOperator op, 1104 bool reuse_assembly_data) { 1105 int ierr; 1106 bool is_composite; 1107 1108 ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1109 if (is_composite) { 1110 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1111 ierr = CeedOperatorSetQFunctionAssemblyReuse(op->sub_operators[i], 1112 reuse_assembly_data); CeedChk(ierr); 1113 } 1114 } else { 1115 ierr = CeedQFunctionAssemblyDataSetReuse(op->qf_assembled, reuse_assembly_data); 1116 CeedChk(ierr); 1117 } 1118 1119 return CEED_ERROR_SUCCESS; 1120 } 1121 1122 /** 1123 @brief Mark CeedQFunction data as updated and the CeedQFunction as requiring re-assembly. 1124 1125 @param[in] op CeedOperator 1126 @param[in] needs_data_update Boolean flag setting assembly data reuse 1127 1128 @return An error code: 0 - success, otherwise - failure 1129 1130 @ref Advanced 1131 **/ 1132 int CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(CeedOperator op, 1133 bool needs_data_update) { 1134 int ierr; 1135 bool is_composite; 1136 1137 ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1138 if (is_composite) { 1139 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1140 ierr = CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(op->sub_operators[i], 1141 needs_data_update); CeedChk(ierr); 1142 } 1143 } else { 1144 ierr = CeedQFunctionAssemblyDataSetUpdateNeeded(op->qf_assembled, 1145 needs_data_update); 1146 CeedChk(ierr); 1147 } 1148 1149 return CEED_ERROR_SUCCESS; 1150 } 1151 1152 /** 1153 @brief Set the number of quadrature points associated with a CeedOperator. 1154 This should be used when creating a CeedOperator where every 1155 field has a collocated basis. This function cannot be used for 1156 composite CeedOperators. 1157 1158 @param op CeedOperator 1159 @param num_qpts Number of quadrature points to set 1160 1161 @return An error code: 0 - success, otherwise - failure 1162 1163 @ref Advanced 1164 **/ 1165 int CeedOperatorSetNumQuadraturePoints(CeedOperator op, CeedInt num_qpts) { 1166 if (op->is_composite) 1167 // LCOV_EXCL_START 1168 return CeedError(op->ceed, CEED_ERROR_MINOR, 1169 "Not defined for composite operator"); 1170 // LCOV_EXCL_STOP 1171 if (op->num_qpts) 1172 // LCOV_EXCL_START 1173 return CeedError(op->ceed, CEED_ERROR_MINOR, 1174 "Number of quadrature points already defined"); 1175 // LCOV_EXCL_STOP 1176 if (op->is_immutable) 1177 // LCOV_EXCL_START 1178 return CeedError(op->ceed, CEED_ERROR_MAJOR, 1179 "Operator cannot be changed after set as immutable"); 1180 // LCOV_EXCL_STOP 1181 1182 op->num_qpts = num_qpts; 1183 return CEED_ERROR_SUCCESS; 1184 } 1185 1186 /** 1187 @brief Set name of CeedOperator for CeedOperatorView output 1188 1189 @param op CeedOperator 1190 @param name Name to set, or NULL to remove previously set name 1191 1192 @return An error code: 0 - success, otherwise - failure 1193 1194 @ref User 1195 **/ 1196 int CeedOperatorSetName(CeedOperator op, const char *name) { 1197 int ierr; 1198 char *name_copy; 1199 size_t name_len = name ? strlen(name) : 0; 1200 1201 ierr = CeedFree(&op->name); CeedChk(ierr); 1202 if (name_len > 0) { 1203 ierr = CeedCalloc(name_len + 1, &name_copy); CeedChk(ierr); 1204 memcpy(name_copy, name, name_len); 1205 op->name = name_copy; 1206 } 1207 1208 return CEED_ERROR_SUCCESS; 1209 } 1210 1211 /** 1212 @brief View a CeedOperator 1213 1214 @param[in] op CeedOperator to view 1215 @param[in] stream Stream to write; typically stdout/stderr or a file 1216 1217 @return Error code: 0 - success, otherwise - failure 1218 1219 @ref User 1220 **/ 1221 int CeedOperatorView(CeedOperator op, FILE *stream) { 1222 int ierr; 1223 bool has_name = op->name; 1224 1225 if (op->is_composite) { 1226 fprintf(stream, "Composite CeedOperator%s%s\n", 1227 has_name ? " - " : "", has_name ? op->name : ""); 1228 1229 for (CeedInt i=0; i<op->num_suboperators; i++) { 1230 has_name = op->sub_operators[i]->name; 1231 fprintf(stream, " SubOperator %" CeedInt_FMT "%s%s:\n", i, 1232 has_name ? " - " : "", 1233 has_name ? op->sub_operators[i]->name : ""); 1234 ierr = CeedOperatorSingleView(op->sub_operators[i], 1, stream); 1235 CeedChk(ierr); 1236 } 1237 } else { 1238 fprintf(stream, "CeedOperator%s%s\n", 1239 has_name ? " - " : "", has_name ? op->name : ""); 1240 ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr); 1241 } 1242 return CEED_ERROR_SUCCESS; 1243 } 1244 1245 /** 1246 @brief Get the Ceed associated with a CeedOperator 1247 1248 @param op CeedOperator 1249 @param[out] ceed Variable to store Ceed 1250 1251 @return An error code: 0 - success, otherwise - failure 1252 1253 @ref Advanced 1254 **/ 1255 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) { 1256 *ceed = op->ceed; 1257 return CEED_ERROR_SUCCESS; 1258 } 1259 1260 /** 1261 @brief Get the number of elements associated with a CeedOperator 1262 1263 @param op CeedOperator 1264 @param[out] num_elem Variable to store number of elements 1265 1266 @return An error code: 0 - success, otherwise - failure 1267 1268 @ref Advanced 1269 **/ 1270 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) { 1271 if (op->is_composite) 1272 // LCOV_EXCL_START 1273 return CeedError(op->ceed, CEED_ERROR_MINOR, 1274 "Not defined for composite operator"); 1275 // LCOV_EXCL_STOP 1276 1277 *num_elem = op->num_elem; 1278 return CEED_ERROR_SUCCESS; 1279 } 1280 1281 /** 1282 @brief Get the number of quadrature points associated with a CeedOperator 1283 1284 @param op CeedOperator 1285 @param[out] num_qpts Variable to store vector number of quadrature points 1286 1287 @return An error code: 0 - success, otherwise - failure 1288 1289 @ref Advanced 1290 **/ 1291 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) { 1292 if (op->is_composite) 1293 // LCOV_EXCL_START 1294 return CeedError(op->ceed, CEED_ERROR_MINOR, 1295 "Not defined for composite operator"); 1296 // LCOV_EXCL_STOP 1297 1298 *num_qpts = op->num_qpts; 1299 return CEED_ERROR_SUCCESS; 1300 } 1301 1302 /** 1303 @brief Estimate number of FLOPs required to apply CeedOperator on the active vector 1304 1305 @param op Operator to estimate FLOPs for 1306 @param flops Address of variable to hold FLOPs estimate 1307 1308 @ref Backend 1309 **/ 1310 int CeedOperatorGetFlopsEstimate(CeedOperator op, CeedSize *flops) { 1311 int ierr; 1312 bool is_composite; 1313 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1314 1315 *flops = 0; 1316 ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1317 if (is_composite) { 1318 CeedInt num_suboperators; 1319 ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1320 CeedOperator *sub_operators; 1321 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1322 1323 // FLOPs for each suboperator 1324 for (CeedInt i = 0; i < num_suboperators; i++) { 1325 CeedSize suboperator_flops; 1326 ierr = CeedOperatorGetFlopsEstimate(sub_operators[i], &suboperator_flops); 1327 CeedChk(ierr); 1328 *flops += suboperator_flops; 1329 } 1330 } else { 1331 CeedInt num_input_fields, num_output_fields; 1332 CeedOperatorField *input_fields, *output_fields; 1333 1334 ierr = CeedOperatorGetFields(op, &num_input_fields, &input_fields, 1335 &num_output_fields, &output_fields); CeedChk(ierr); 1336 1337 CeedInt num_elem = 0; 1338 ierr = CeedOperatorGetNumElements(op, &num_elem); CeedChk(ierr); 1339 // Input FLOPs 1340 for (CeedInt i = 0; i < num_input_fields; i++) { 1341 if (input_fields[i]->vec == CEED_VECTOR_ACTIVE) { 1342 CeedSize restr_flops, basis_flops; 1343 1344 ierr = CeedElemRestrictionGetFlopsEstimate(input_fields[i]->elem_restr, 1345 CEED_NOTRANSPOSE, &restr_flops); CeedChk(ierr); 1346 *flops += restr_flops; 1347 ierr = CeedBasisGetFlopsEstimate(input_fields[i]->basis, CEED_NOTRANSPOSE, 1348 op->qf->input_fields[i]->eval_mode, &basis_flops); CeedChk(ierr); 1349 *flops += basis_flops * num_elem; 1350 } 1351 } 1352 // QF FLOPs 1353 CeedInt num_qpts; 1354 CeedSize qf_flops; 1355 ierr = CeedOperatorGetNumQuadraturePoints(op, &num_qpts); CeedChk(ierr); 1356 ierr = CeedQFunctionGetFlopsEstimate(op->qf, &qf_flops); CeedChk(ierr); 1357 *flops += num_elem * num_qpts * qf_flops; 1358 // Output FLOPs 1359 for (CeedInt i = 0; i < num_output_fields; i++) { 1360 if (output_fields[i]->vec == CEED_VECTOR_ACTIVE) { 1361 CeedSize restr_flops, basis_flops; 1362 1363 ierr = CeedElemRestrictionGetFlopsEstimate(output_fields[i]->elem_restr, 1364 CEED_TRANSPOSE, &restr_flops); CeedChk(ierr); 1365 *flops += restr_flops; 1366 ierr = CeedBasisGetFlopsEstimate(output_fields[i]->basis, CEED_TRANSPOSE, 1367 op->qf->output_fields[i]->eval_mode, &basis_flops); CeedChk(ierr); 1368 *flops += basis_flops * num_elem; 1369 } 1370 } 1371 } 1372 1373 return CEED_ERROR_SUCCESS; 1374 } 1375 1376 /** 1377 @brief Get label for a registered QFunctionContext field, or `NULL` if no 1378 field has been registered with this `field_name`. 1379 1380 @param[in] op CeedOperator 1381 @param[in] field_name Name of field to retrieve label 1382 @param[out] field_label Variable to field label 1383 1384 @return An error code: 0 - success, otherwise - failure 1385 1386 @ref User 1387 **/ 1388 int CeedOperatorContextGetFieldLabel(CeedOperator op, 1389 const char *field_name, 1390 CeedContextFieldLabel *field_label) { 1391 int ierr; 1392 1393 bool is_composite; 1394 ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1395 if (is_composite) { 1396 // Check if composite label already created 1397 for (CeedInt i=0; i<op->num_context_labels; i++) { 1398 if (!strcmp(op->context_labels[i]->name, field_name)) { 1399 *field_label = op->context_labels[i]; 1400 return CEED_ERROR_SUCCESS; 1401 } 1402 } 1403 1404 // Create composite label if needed 1405 CeedInt num_sub; 1406 CeedOperator *sub_operators; 1407 CeedContextFieldLabel new_field_label; 1408 1409 ierr = CeedCalloc(1, &new_field_label); CeedChk(ierr); 1410 ierr = CeedOperatorGetNumSub(op, &num_sub); CeedChk(ierr); 1411 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1412 ierr = CeedCalloc(num_sub, &new_field_label->sub_labels); CeedChk(ierr); 1413 new_field_label->num_sub_labels = num_sub; 1414 1415 bool label_found = false; 1416 for (CeedInt i=0; i<num_sub; i++) { 1417 if (sub_operators[i]->qf->ctx) { 1418 CeedContextFieldLabel new_field_label_i; 1419 ierr = CeedQFunctionContextGetFieldLabel(sub_operators[i]->qf->ctx, field_name, 1420 &new_field_label_i); CeedChk(ierr); 1421 if (new_field_label_i) { 1422 label_found = true; 1423 new_field_label->sub_labels[i] = new_field_label_i; 1424 new_field_label->name = new_field_label_i->name; 1425 new_field_label->description = new_field_label_i->description; 1426 if (new_field_label->type && 1427 new_field_label->type != new_field_label_i->type) { 1428 // LCOV_EXCL_START 1429 ierr = CeedFree(&new_field_label); CeedChk(ierr); 1430 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 1431 "Incompatible field types on sub-operator contexts. " 1432 "%s != %s", 1433 CeedContextFieldTypes[new_field_label->type], 1434 CeedContextFieldTypes[new_field_label_i->type]); 1435 // LCOV_EXCL_STOP 1436 } else { 1437 new_field_label->type = new_field_label_i->type; 1438 } 1439 if (new_field_label->num_values != 0 && 1440 new_field_label->num_values != new_field_label_i->num_values) { 1441 // LCOV_EXCL_START 1442 ierr = CeedFree(&new_field_label); CeedChk(ierr); 1443 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 1444 "Incompatible field number of values on sub-operator" 1445 " contexts. %ld != %ld", 1446 new_field_label->num_values, new_field_label_i->num_values); 1447 // LCOV_EXCL_STOP 1448 } else { 1449 new_field_label->num_values = new_field_label_i->num_values; 1450 } 1451 } 1452 } 1453 } 1454 if (!label_found) { 1455 // LCOV_EXCL_START 1456 ierr = CeedFree(&new_field_label->sub_labels); CeedChk(ierr); 1457 ierr = CeedFree(&new_field_label); CeedChk(ierr); 1458 *field_label = NULL; 1459 // LCOV_EXCL_STOP 1460 } else { 1461 // Move new composite label to operator 1462 if (op->num_context_labels == 0) { 1463 ierr = CeedCalloc(1, &op->context_labels); CeedChk(ierr); 1464 op->max_context_labels = 1; 1465 } else if (op->num_context_labels == op->max_context_labels) { 1466 ierr = CeedRealloc(2*op->num_context_labels, &op->context_labels); 1467 CeedChk(ierr); 1468 op->max_context_labels *= 2; 1469 } 1470 op->context_labels[op->num_context_labels] = new_field_label; 1471 *field_label = new_field_label; 1472 op->num_context_labels++; 1473 } 1474 1475 return CEED_ERROR_SUCCESS; 1476 } else { 1477 return CeedQFunctionContextGetFieldLabel(op->qf->ctx, field_name, field_label); 1478 } 1479 } 1480 1481 /** 1482 @brief Set QFunctionContext field holding a double precision value. 1483 For composite operators, the value is set in all 1484 sub-operator QFunctionContexts that have a matching `field_name`. 1485 1486 @param op CeedOperator 1487 @param field_label Label of field to register 1488 @param values Values to set 1489 1490 @return An error code: 0 - success, otherwise - failure 1491 1492 @ref User 1493 **/ 1494 int CeedOperatorContextSetDouble(CeedOperator op, 1495 CeedContextFieldLabel field_label, 1496 double *values) { 1497 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, 1498 values); 1499 } 1500 1501 /** 1502 @brief Set QFunctionContext field holding an int32 value. 1503 For composite operators, the value is set in all 1504 sub-operator QFunctionContexts that have a matching `field_name`. 1505 1506 @param op CeedOperator 1507 @param field_label Label of field to set 1508 @param values Values to set 1509 1510 @return An error code: 0 - success, otherwise - failure 1511 1512 @ref User 1513 **/ 1514 int CeedOperatorContextSetInt32(CeedOperator op, 1515 CeedContextFieldLabel field_label, 1516 int *values) { 1517 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_INT32, 1518 values); 1519 } 1520 1521 /** 1522 @brief Apply CeedOperator to a vector 1523 1524 This computes the action of the operator on the specified (active) input, 1525 yielding its (active) output. All inputs and outputs must be specified using 1526 CeedOperatorSetField(). 1527 1528 Note: Calling this function asserts that setup is complete 1529 and sets the CeedOperator as immutable. 1530 1531 @param op CeedOperator to apply 1532 @param[in] in CeedVector containing input state or @ref CEED_VECTOR_NONE if 1533 there are no active inputs 1534 @param[out] out CeedVector to store result of applying operator (must be 1535 distinct from @a in) or @ref CEED_VECTOR_NONE if there are no 1536 active outputs 1537 @param request Address of CeedRequest for non-blocking completion, else 1538 @ref CEED_REQUEST_IMMEDIATE 1539 1540 @return An error code: 0 - success, otherwise - failure 1541 1542 @ref User 1543 **/ 1544 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, 1545 CeedRequest *request) { 1546 int ierr; 1547 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1548 1549 if (op->num_elem) { 1550 // Standard Operator 1551 if (op->Apply) { 1552 ierr = op->Apply(op, in, out, request); CeedChk(ierr); 1553 } else { 1554 // Zero all output vectors 1555 CeedQFunction qf = op->qf; 1556 for (CeedInt i=0; i<qf->num_output_fields; i++) { 1557 CeedVector vec = op->output_fields[i]->vec; 1558 if (vec == CEED_VECTOR_ACTIVE) 1559 vec = out; 1560 if (vec != CEED_VECTOR_NONE) { 1561 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 1562 } 1563 } 1564 // Apply 1565 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 1566 } 1567 } else if (op->is_composite) { 1568 // Composite Operator 1569 if (op->ApplyComposite) { 1570 ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr); 1571 } else { 1572 CeedInt num_suboperators; 1573 ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1574 CeedOperator *sub_operators; 1575 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1576 1577 // Zero all output vectors 1578 if (out != CEED_VECTOR_NONE) { 1579 ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr); 1580 } 1581 for (CeedInt i=0; i<num_suboperators; i++) { 1582 for (CeedInt j=0; j<sub_operators[i]->qf->num_output_fields; j++) { 1583 CeedVector vec = sub_operators[i]->output_fields[j]->vec; 1584 if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) { 1585 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 1586 } 1587 } 1588 } 1589 // Apply 1590 for (CeedInt i=0; i<op->num_suboperators; i++) { 1591 ierr = CeedOperatorApplyAdd(op->sub_operators[i], in, out, request); 1592 CeedChk(ierr); 1593 } 1594 } 1595 } 1596 return CEED_ERROR_SUCCESS; 1597 } 1598 1599 /** 1600 @brief Apply CeedOperator to a vector and add result to output vector 1601 1602 This computes the action of the operator on the specified (active) input, 1603 yielding its (active) output. All inputs and outputs must be specified using 1604 CeedOperatorSetField(). 1605 1606 @param op CeedOperator to apply 1607 @param[in] in CeedVector containing input state or NULL if there are no 1608 active inputs 1609 @param[out] out CeedVector to sum in result of applying operator (must be 1610 distinct from @a in) or NULL if there are no active outputs 1611 @param request Address of CeedRequest for non-blocking completion, else 1612 @ref CEED_REQUEST_IMMEDIATE 1613 1614 @return An error code: 0 - success, otherwise - failure 1615 1616 @ref User 1617 **/ 1618 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, 1619 CeedRequest *request) { 1620 int ierr; 1621 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1622 1623 if (op->num_elem) { 1624 // Standard Operator 1625 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 1626 } else if (op->is_composite) { 1627 // Composite Operator 1628 if (op->ApplyAddComposite) { 1629 ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr); 1630 } else { 1631 CeedInt num_suboperators; 1632 ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1633 CeedOperator *sub_operators; 1634 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1635 1636 for (CeedInt i=0; i<num_suboperators; i++) { 1637 ierr = CeedOperatorApplyAdd(sub_operators[i], in, out, request); 1638 CeedChk(ierr); 1639 } 1640 } 1641 } 1642 return CEED_ERROR_SUCCESS; 1643 } 1644 1645 /** 1646 @brief Destroy a CeedOperator 1647 1648 @param op CeedOperator to destroy 1649 1650 @return An error code: 0 - success, otherwise - failure 1651 1652 @ref User 1653 **/ 1654 int CeedOperatorDestroy(CeedOperator *op) { 1655 int ierr; 1656 1657 if (!*op || --(*op)->ref_count > 0) return CEED_ERROR_SUCCESS; 1658 if ((*op)->Destroy) { 1659 ierr = (*op)->Destroy(*op); CeedChk(ierr); 1660 } 1661 ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr); 1662 // Free fields 1663 for (CeedInt i=0; i<(*op)->num_fields; i++) 1664 if ((*op)->input_fields[i]) { 1665 if ((*op)->input_fields[i]->elem_restr != CEED_ELEMRESTRICTION_NONE) { 1666 ierr = CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_restr); 1667 CeedChk(ierr); 1668 } 1669 if ((*op)->input_fields[i]->basis != CEED_BASIS_COLLOCATED) { 1670 ierr = CeedBasisDestroy(&(*op)->input_fields[i]->basis); CeedChk(ierr); 1671 } 1672 if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE && 1673 (*op)->input_fields[i]->vec != CEED_VECTOR_NONE ) { 1674 ierr = CeedVectorDestroy(&(*op)->input_fields[i]->vec); CeedChk(ierr); 1675 } 1676 ierr = CeedFree(&(*op)->input_fields[i]->field_name); CeedChk(ierr); 1677 ierr = CeedFree(&(*op)->input_fields[i]); CeedChk(ierr); 1678 } 1679 for (CeedInt i=0; i<(*op)->num_fields; i++) 1680 if ((*op)->output_fields[i]) { 1681 ierr = CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_restr); 1682 CeedChk(ierr); 1683 if ((*op)->output_fields[i]->basis != CEED_BASIS_COLLOCATED) { 1684 ierr = CeedBasisDestroy(&(*op)->output_fields[i]->basis); CeedChk(ierr); 1685 } 1686 if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE && 1687 (*op)->output_fields[i]->vec != CEED_VECTOR_NONE ) { 1688 ierr = CeedVectorDestroy(&(*op)->output_fields[i]->vec); CeedChk(ierr); 1689 } 1690 ierr = CeedFree(&(*op)->output_fields[i]->field_name); CeedChk(ierr); 1691 ierr = CeedFree(&(*op)->output_fields[i]); CeedChk(ierr); 1692 } 1693 // Destroy sub_operators 1694 for (CeedInt i=0; i<(*op)->num_suboperators; i++) 1695 if ((*op)->sub_operators[i]) { 1696 ierr = CeedOperatorDestroy(&(*op)->sub_operators[i]); CeedChk(ierr); 1697 } 1698 ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr); 1699 ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr); 1700 ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr); 1701 // Destroy any composite labels 1702 for (CeedInt i=0; i<(*op)->num_context_labels; i++) { 1703 ierr = CeedFree(&(*op)->context_labels[i]->sub_labels); CeedChk(ierr); 1704 ierr = CeedFree(&(*op)->context_labels[i]); CeedChk(ierr); 1705 } 1706 ierr = CeedFree(&(*op)->context_labels); CeedChk(ierr); 1707 1708 // Destroy fallback 1709 ierr = CeedOperatorDestroy(&(*op)->op_fallback); CeedChk(ierr); 1710 1711 // Destroy assembly data 1712 ierr = CeedQFunctionAssemblyDataDestroy(&(*op)->qf_assembled); CeedChk(ierr); 1713 ierr = CeedOperatorAssemblyDataDestroy(&(*op)->op_assembled); CeedChk(ierr); 1714 1715 ierr = CeedFree(&(*op)->input_fields); CeedChk(ierr); 1716 ierr = CeedFree(&(*op)->output_fields); CeedChk(ierr); 1717 ierr = CeedFree(&(*op)->sub_operators); CeedChk(ierr); 1718 ierr = CeedFree(&(*op)->name); CeedChk(ierr); 1719 ierr = CeedFree(op); CeedChk(ierr); 1720 return CEED_ERROR_SUCCESS; 1721 } 1722 1723 /// @} 1724