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, Q_comp = 1, restr_num_comp = 1, 41 size = qf_field->size; 42 // Restriction 43 if (r != CEED_ELEMRESTRICTION_NONE) { 44 if (eval_mode == CEED_EVAL_WEIGHT) { 45 // LCOV_EXCL_START 46 return CeedError(ceed, CEED_ERROR_INCOMPATIBLE, 47 "CEED_ELEMRESTRICTION_NONE should be used " 48 "for a field with eval mode CEED_EVAL_WEIGHT"); 49 // LCOV_EXCL_STOP 50 } 51 ierr = CeedElemRestrictionGetNumComponents(r, &restr_num_comp); 52 CeedChk(ierr); 53 } 54 if ((r == CEED_ELEMRESTRICTION_NONE) != (eval_mode == CEED_EVAL_WEIGHT)) { 55 // LCOV_EXCL_START 56 return CeedError(ceed, CEED_ERROR_INCOMPATIBLE, 57 "CEED_ELEMRESTRICTION_NONE and CEED_EVAL_WEIGHT " 58 "must be used together."); 59 // LCOV_EXCL_STOP 60 } 61 // Basis 62 if (b != CEED_BASIS_COLLOCATED) { 63 if (eval_mode == CEED_EVAL_NONE) 64 // LCOV_EXCL_START 65 return CeedError(ceed, CEED_ERROR_INCOMPATIBLE, 66 "Field '%s' configured with CEED_EVAL_NONE must " 67 "be used with CEED_BASIS_COLLOCATED", 68 qf_field->field_name); 69 // LCOV_EXCL_STOP 70 ierr = CeedBasisGetDimension(b, &dim); CeedChk(ierr); 71 ierr = CeedBasisGetNumComponents(b, &num_comp); CeedChk(ierr); 72 ierr = CeedBasisGetNumQuadratureComponents(b, &Q_comp); CeedChk(ierr); 73 if (r != CEED_ELEMRESTRICTION_NONE && restr_num_comp != num_comp) { 74 // LCOV_EXCL_START 75 return CeedError(ceed, CEED_ERROR_DIMENSION, 76 "Field '%s' of size %" CeedInt_FMT " and EvalMode %s: ElemRestriction " 77 "has %" CeedInt_FMT " components, but Basis has %" CeedInt_FMT " components", 78 qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], 79 restr_num_comp, num_comp); 80 // LCOV_EXCL_STOP 81 } 82 } else if (eval_mode != CEED_EVAL_NONE) { 83 // LCOV_EXCL_START 84 return CeedError(ceed, CEED_ERROR_INCOMPATIBLE, 85 "Field '%s' configured with %s cannot " 86 "be used with CEED_BASIS_COLLOCATED", 87 qf_field->field_name, CeedEvalModes[eval_mode]); 88 // LCOV_EXCL_STOP 89 90 } 91 // Field size 92 switch(eval_mode) { 93 case CEED_EVAL_NONE: 94 if (size != restr_num_comp) 95 // LCOV_EXCL_START 96 return CeedError(ceed, CEED_ERROR_DIMENSION, 97 "Field '%s' of size %" CeedInt_FMT " and EvalMode %s: ElemRestriction has " 98 CeedInt_FMT " components", 99 qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], 100 restr_num_comp); 101 // LCOV_EXCL_STOP 102 break; 103 case CEED_EVAL_INTERP: 104 if (size != num_comp*Q_comp) 105 // LCOV_EXCL_START 106 return CeedError(ceed, CEED_ERROR_DIMENSION, 107 "Field '%s' of size %" CeedInt_FMT 108 " and EvalMode %s: ElemRestriction/Basis has " 109 CeedInt_FMT " components", 110 qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], 111 num_comp*Q_comp); 112 // LCOV_EXCL_STOP 113 break; 114 case CEED_EVAL_GRAD: 115 if (size != num_comp * dim) 116 // LCOV_EXCL_START 117 return CeedError(ceed, CEED_ERROR_DIMENSION, 118 "Field '%s' of size %" CeedInt_FMT " and EvalMode %s in %" CeedInt_FMT 119 " dimensions: " 120 "ElemRestriction/Basis has %" CeedInt_FMT " components", 121 qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], dim, 122 num_comp); 123 // LCOV_EXCL_STOP 124 break; 125 case CEED_EVAL_WEIGHT: 126 // No additional checks required 127 break; 128 case CEED_EVAL_DIV: 129 if (size != num_comp) 130 // LCOV_EXCL_START 131 return CeedError(ceed, CEED_ERROR_DIMENSION, 132 "Field '%s' of size %" CeedInt_FMT 133 " and EvalMode %s: ElemRestriction/Basis has " 134 CeedInt_FMT " components", 135 qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], 136 num_comp); 137 // LCOV_EXCL_STOP 138 break; 139 case CEED_EVAL_CURL: 140 // Not implemented 141 break; 142 } 143 return CEED_ERROR_SUCCESS; 144 } 145 146 /** 147 @brief View a field of a CeedOperator 148 149 @param[in] field Operator field to view 150 @param[in] qf_field QFunction field (carries field name) 151 @param[in] field_number Number of field being viewed 152 @param[in] sub true indicates sub-operator, which increases indentation; false for top-level operator 153 @param[in] input true for an input field; false for output field 154 @param[in] stream Stream to view to, e.g., stdout 155 156 @return An error code: 0 - success, otherwise - failure 157 158 @ref Utility 159 **/ 160 static int CeedOperatorFieldView(CeedOperatorField field, 161 CeedQFunctionField qf_field, 162 CeedInt field_number, bool sub, bool input, 163 FILE *stream) { 164 const char *pre = sub ? " " : ""; 165 const char *in_out = input ? "Input" : "Output"; 166 167 fprintf(stream, "%s %s field %" CeedInt_FMT ":\n" 168 "%s Name: \"%s\"\n", 169 pre, in_out, field_number, pre, qf_field->field_name); 170 171 fprintf(stream, "%s Size: %" CeedInt_FMT "\n", pre, qf_field->size); 172 173 fprintf(stream, "%s EvalMode: %s\n", pre, 174 CeedEvalModes[qf_field->eval_mode]); 175 176 if (field->basis == CEED_BASIS_COLLOCATED) 177 fprintf(stream, "%s Collocated basis\n", pre); 178 179 if (field->vec == CEED_VECTOR_ACTIVE) 180 fprintf(stream, "%s Active vector\n", pre); 181 else if (field->vec == CEED_VECTOR_NONE) 182 fprintf(stream, "%s No vector\n", pre); 183 184 return CEED_ERROR_SUCCESS; 185 } 186 187 /** 188 @brief View a single CeedOperator 189 190 @param[in] op CeedOperator to view 191 @param[in] sub Boolean flag for sub-operator 192 @param[in] stream Stream to write; typically stdout/stderr or a file 193 194 @return Error code: 0 - success, otherwise - failure 195 196 @ref Utility 197 **/ 198 int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) { 199 int ierr; 200 const char *pre = sub ? " " : ""; 201 202 CeedInt num_elem, num_qpts; 203 ierr = CeedOperatorGetNumElements(op, &num_elem); CeedChk(ierr); 204 ierr = CeedOperatorGetNumQuadraturePoints(op, &num_qpts); CeedChk(ierr); 205 206 CeedInt total_fields = 0; 207 ierr = CeedOperatorGetNumArgs(op, &total_fields); CeedChk(ierr); 208 fprintf(stream, "%s %" CeedInt_FMT " elements with %" CeedInt_FMT 209 " quadrature points each\n", 210 pre, num_elem, num_qpts); 211 212 fprintf(stream, "%s %" CeedInt_FMT " field%s\n", pre, total_fields, 213 total_fields>1 ? "s" : ""); 214 215 fprintf(stream, "%s %" CeedInt_FMT " input field%s:\n", pre, 216 op->qf->num_input_fields, 217 op->qf->num_input_fields>1 ? "s" : ""); 218 for (CeedInt i=0; i<op->qf->num_input_fields; i++) { 219 ierr = CeedOperatorFieldView(op->input_fields[i], op->qf->input_fields[i], 220 i, sub, 1, stream); CeedChk(ierr); 221 } 222 223 fprintf(stream, "%s %" CeedInt_FMT " output field%s:\n", pre, 224 op->qf->num_output_fields, 225 op->qf->num_output_fields>1 ? "s" : ""); 226 for (CeedInt i=0; i<op->qf->num_output_fields; i++) { 227 ierr = CeedOperatorFieldView(op->output_fields[i], op->qf->output_fields[i], 228 i, sub, 0, stream); CeedChk(ierr); 229 } 230 return CEED_ERROR_SUCCESS; 231 } 232 233 /** 234 @brief Find the active vector basis for a non-composite CeedOperator 235 236 @param[in] op CeedOperator to find active basis for 237 @param[out] active_basis Basis for active input vector or NULL for composite operator 238 239 @return An error code: 0 - success, otherwise - failure 240 241 @ ref Developer 242 **/ 243 int CeedOperatorGetActiveBasis(CeedOperator op, CeedBasis *active_basis) { 244 *active_basis = NULL; 245 if (op->is_composite) return CEED_ERROR_SUCCESS; 246 for (CeedInt i = 0; i < op->qf->num_input_fields; i++) 247 if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) { 248 *active_basis = op->input_fields[i]->basis; 249 break; 250 } 251 252 if (!*active_basis) { 253 // LCOV_EXCL_START 254 int ierr; 255 Ceed ceed; 256 ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); 257 return CeedError(ceed, CEED_ERROR_MINOR, 258 "No active CeedBasis found"); 259 // LCOV_EXCL_STOP 260 } 261 return CEED_ERROR_SUCCESS; 262 } 263 264 /** 265 @brief Find the active vector ElemRestriction for a non-composite CeedOperator 266 267 @param[in] op CeedOperator to find active basis for 268 @param[out] active_rstr ElemRestriction for active input vector or NULL for composite operator 269 270 @return An error code: 0 - success, otherwise - failure 271 272 @ref Utility 273 **/ 274 int CeedOperatorGetActiveElemRestriction(CeedOperator op, 275 CeedElemRestriction *active_rstr) { 276 *active_rstr = NULL; 277 if (op->is_composite) return CEED_ERROR_SUCCESS; 278 for (CeedInt i = 0; i < op->qf->num_input_fields; i++) 279 if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) { 280 *active_rstr = op->input_fields[i]->elem_restr; 281 break; 282 } 283 284 if (!*active_rstr) { 285 // LCOV_EXCL_START 286 int ierr; 287 Ceed ceed; 288 ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); 289 return CeedError(ceed, CEED_ERROR_INCOMPLETE, 290 "No active CeedElemRestriction found"); 291 // LCOV_EXCL_STOP 292 } 293 return CEED_ERROR_SUCCESS; 294 } 295 296 /** 297 @brief Set QFunctionContext field value of the specified type. 298 For composite operators, the value is set in all 299 sub-operator QFunctionContexts that have a matching `field_name`. 300 A non-zero error code is returned for single operators 301 that do not have a matching field of the same type or composite 302 operators that do not have any field of a matching type. 303 304 @param op CeedOperator 305 @param field_label Label of field to set 306 @param field_type Type of field to set 307 @param value Value to set 308 309 @return An error code: 0 - success, otherwise - failure 310 311 @ref User 312 **/ 313 static int CeedOperatorContextSetGeneric(CeedOperator op, 314 CeedContextFieldLabel field_label, CeedContextFieldType field_type, 315 void *value) { 316 int ierr; 317 318 if (!field_label) 319 // LCOV_EXCL_START 320 return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, 321 "Invalid field label"); 322 // LCOV_EXCL_STOP 323 324 bool is_composite = false; 325 ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 326 if (is_composite) { 327 CeedInt num_sub; 328 CeedOperator *sub_operators; 329 330 ierr = CeedOperatorGetNumSub(op, &num_sub); CeedChk(ierr); 331 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 332 if (num_sub != field_label->num_sub_labels) 333 // LCOV_EXCL_START 334 return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, 335 "ContextLabel does not correspond to composite operator.\n" 336 "Use CeedOperatorGetContextFieldLabel()."); 337 // LCOV_EXCL_STOP 338 339 for (CeedInt i = 0; i < num_sub; i++) { 340 // Try every sub-operator, ok if some sub-operators do not have field 341 if (field_label->sub_labels[i] && sub_operators[i]->qf->ctx) { 342 ierr = CeedQFunctionContextSetGeneric(sub_operators[i]->qf->ctx, 343 field_label->sub_labels[i], 344 field_type, value); CeedChk(ierr); 345 } 346 } 347 } else { 348 if (!op->qf->ctx) 349 // LCOV_EXCL_START 350 return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, 351 "QFunction does not have context data"); 352 // LCOV_EXCL_STOP 353 354 ierr = CeedQFunctionContextSetGeneric(op->qf->ctx, field_label, 355 field_type, value); CeedChk(ierr); 356 } 357 358 return CEED_ERROR_SUCCESS; 359 } 360 361 /// @} 362 363 /// ---------------------------------------------------------------------------- 364 /// CeedOperator Backend API 365 /// ---------------------------------------------------------------------------- 366 /// @addtogroup CeedOperatorBackend 367 /// @{ 368 369 /** 370 @brief Get the number of arguments associated with a CeedOperator 371 372 @param op CeedOperator 373 @param[out] num_args Variable to store vector number of arguments 374 375 @return An error code: 0 - success, otherwise - failure 376 377 @ref Backend 378 **/ 379 380 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *num_args) { 381 if (op->is_composite) 382 // LCOV_EXCL_START 383 return CeedError(op->ceed, CEED_ERROR_MINOR, 384 "Not defined for composite operators"); 385 // LCOV_EXCL_STOP 386 387 *num_args = op->num_fields; 388 return CEED_ERROR_SUCCESS; 389 } 390 391 /** 392 @brief Get the setup status of a CeedOperator 393 394 @param op CeedOperator 395 @param[out] is_setup_done Variable to store setup status 396 397 @return An error code: 0 - success, otherwise - failure 398 399 @ref Backend 400 **/ 401 402 int CeedOperatorIsSetupDone(CeedOperator op, bool *is_setup_done) { 403 *is_setup_done = op->is_backend_setup; 404 return CEED_ERROR_SUCCESS; 405 } 406 407 /** 408 @brief Get the QFunction associated with a CeedOperator 409 410 @param op CeedOperator 411 @param[out] qf Variable to store QFunction 412 413 @return An error code: 0 - success, otherwise - failure 414 415 @ref Backend 416 **/ 417 418 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) { 419 if (op->is_composite) 420 // LCOV_EXCL_START 421 return CeedError(op->ceed, CEED_ERROR_MINOR, 422 "Not defined for composite operator"); 423 // LCOV_EXCL_STOP 424 425 *qf = op->qf; 426 return CEED_ERROR_SUCCESS; 427 } 428 429 /** 430 @brief Get a boolean value indicating if the CeedOperator is composite 431 432 @param op CeedOperator 433 @param[out] is_composite Variable to store composite status 434 435 @return An error code: 0 - success, otherwise - failure 436 437 @ref Backend 438 **/ 439 440 int CeedOperatorIsComposite(CeedOperator op, bool *is_composite) { 441 *is_composite = op->is_composite; 442 return CEED_ERROR_SUCCESS; 443 } 444 445 /** 446 @brief Get the number of sub_operators associated with a CeedOperator 447 448 @param op CeedOperator 449 @param[out] num_suboperators Variable to store number of sub_operators 450 451 @return An error code: 0 - success, otherwise - failure 452 453 @ref Backend 454 **/ 455 456 int CeedOperatorGetNumSub(CeedOperator op, CeedInt *num_suboperators) { 457 if (!op->is_composite) 458 // LCOV_EXCL_START 459 return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator"); 460 // LCOV_EXCL_STOP 461 462 *num_suboperators = op->num_suboperators; 463 return CEED_ERROR_SUCCESS; 464 } 465 466 /** 467 @brief Get the list of sub_operators associated with a CeedOperator 468 469 @param op CeedOperator 470 @param[out] sub_operators Variable to store list of sub_operators 471 472 @return An error code: 0 - success, otherwise - failure 473 474 @ref Backend 475 **/ 476 477 int CeedOperatorGetSubList(CeedOperator op, CeedOperator **sub_operators) { 478 if (!op->is_composite) 479 // LCOV_EXCL_START 480 return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator"); 481 // LCOV_EXCL_STOP 482 483 *sub_operators = op->sub_operators; 484 return CEED_ERROR_SUCCESS; 485 } 486 487 /** 488 @brief Get the backend data of a CeedOperator 489 490 @param op CeedOperator 491 @param[out] data Variable to store data 492 493 @return An error code: 0 - success, otherwise - failure 494 495 @ref Backend 496 **/ 497 498 int CeedOperatorGetData(CeedOperator op, void *data) { 499 *(void **)data = op->data; 500 return CEED_ERROR_SUCCESS; 501 } 502 503 /** 504 @brief Set the backend data of a CeedOperator 505 506 @param[out] op CeedOperator 507 @param data Data to set 508 509 @return An error code: 0 - success, otherwise - failure 510 511 @ref Backend 512 **/ 513 514 int CeedOperatorSetData(CeedOperator op, void *data) { 515 op->data = data; 516 return CEED_ERROR_SUCCESS; 517 } 518 519 /** 520 @brief Increment the reference counter for a CeedOperator 521 522 @param op CeedOperator to increment the reference counter 523 524 @return An error code: 0 - success, otherwise - failure 525 526 @ref Backend 527 **/ 528 int CeedOperatorReference(CeedOperator op) { 529 op->ref_count++; 530 return CEED_ERROR_SUCCESS; 531 } 532 533 /** 534 @brief Set the setup flag of a CeedOperator to True 535 536 @param op CeedOperator 537 538 @return An error code: 0 - success, otherwise - failure 539 540 @ref Backend 541 **/ 542 543 int CeedOperatorSetSetupDone(CeedOperator op) { 544 op->is_backend_setup = true; 545 return CEED_ERROR_SUCCESS; 546 } 547 548 /// @} 549 550 /// ---------------------------------------------------------------------------- 551 /// CeedOperator Public API 552 /// ---------------------------------------------------------------------------- 553 /// @addtogroup CeedOperatorUser 554 /// @{ 555 556 /** 557 @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and 558 CeedElemRestriction can be associated with CeedQFunction fields with 559 \ref CeedOperatorSetField. 560 561 @param ceed A Ceed object where the CeedOperator will be created 562 @param qf QFunction defining the action of the operator at quadrature points 563 @param dqf QFunction defining the action of the Jacobian of @a qf (or 564 @ref CEED_QFUNCTION_NONE) 565 @param dqfT QFunction defining the action of the transpose of the Jacobian 566 of @a qf (or @ref CEED_QFUNCTION_NONE) 567 @param[out] op Address of the variable where the newly created 568 CeedOperator will be stored 569 570 @return An error code: 0 - success, otherwise - failure 571 572 @ref User 573 */ 574 int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, 575 CeedQFunction dqfT, CeedOperator *op) { 576 int ierr; 577 578 if (!ceed->OperatorCreate) { 579 Ceed delegate; 580 ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr); 581 582 if (!delegate) 583 // LCOV_EXCL_START 584 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 585 "Backend does not support OperatorCreate"); 586 // LCOV_EXCL_STOP 587 588 ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr); 589 return CEED_ERROR_SUCCESS; 590 } 591 592 if (!qf || qf == CEED_QFUNCTION_NONE) 593 // LCOV_EXCL_START 594 return CeedError(ceed, CEED_ERROR_MINOR, 595 "Operator must have a valid QFunction."); 596 // LCOV_EXCL_STOP 597 ierr = CeedCalloc(1, op); CeedChk(ierr); 598 (*op)->ceed = ceed; 599 ierr = CeedReference(ceed); CeedChk(ierr); 600 (*op)->ref_count = 1; 601 (*op)->qf = qf; 602 (*op)->input_size = -1; 603 (*op)->output_size = -1; 604 ierr = CeedQFunctionReference(qf); CeedChk(ierr); 605 if (dqf && dqf != CEED_QFUNCTION_NONE) { 606 (*op)->dqf = dqf; 607 ierr = CeedQFunctionReference(dqf); CeedChk(ierr); 608 } 609 if (dqfT && dqfT != CEED_QFUNCTION_NONE) { 610 (*op)->dqfT = dqfT; 611 ierr = CeedQFunctionReference(dqfT); CeedChk(ierr); 612 } 613 ierr = CeedQFunctionAssemblyDataCreate(ceed, &(*op)->qf_assembled); 614 CeedChk(ierr); 615 ierr = CeedCalloc(CEED_FIELD_MAX, &(*op)->input_fields); CeedChk(ierr); 616 ierr = CeedCalloc(CEED_FIELD_MAX, &(*op)->output_fields); CeedChk(ierr); 617 ierr = ceed->OperatorCreate(*op); CeedChk(ierr); 618 return CEED_ERROR_SUCCESS; 619 } 620 621 /** 622 @brief Create an operator that composes the action of several operators 623 624 @param ceed A Ceed object where the CeedOperator will be created 625 @param[out] op Address of the variable where the newly created 626 Composite CeedOperator will be stored 627 628 @return An error code: 0 - success, otherwise - failure 629 630 @ref User 631 */ 632 int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) { 633 int ierr; 634 635 if (!ceed->CompositeOperatorCreate) { 636 Ceed delegate; 637 ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr); 638 639 if (delegate) { 640 ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr); 641 return CEED_ERROR_SUCCESS; 642 } 643 } 644 645 ierr = CeedCalloc(1, op); CeedChk(ierr); 646 (*op)->ceed = ceed; 647 ierr = CeedReference(ceed); CeedChk(ierr); 648 (*op)->ref_count = 1; 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