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