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