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 // Empty operator setup 1011 op->input_size = 0; 1012 op->output_size = 0; 1013 } else { 1014 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1015 ierr = CeedOperatorCheckReady(op->sub_operators[i]); CeedChk(ierr); 1016 } 1017 // Sub-operators could be modified after adding to composite operator 1018 // Need to verify no lvec incompatibility from any changes 1019 CeedSize input_size, output_size; 1020 ierr = CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size); 1021 CeedChk(ierr); 1022 } 1023 } else { 1024 if (op->num_fields == 0) 1025 // LCOV_EXCL_START 1026 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No operator fields set"); 1027 // LCOV_EXCL_STOP 1028 if (op->num_fields < qf->num_input_fields + qf->num_output_fields) 1029 // LCOV_EXCL_START 1030 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set"); 1031 // LCOV_EXCL_STOP 1032 if (!op->has_restriction) 1033 // LCOV_EXCL_START 1034 return CeedError(ceed, CEED_ERROR_INCOMPLETE, 1035 "At least one restriction required"); 1036 // LCOV_EXCL_STOP 1037 if (op->num_qpts == 0) 1038 // LCOV_EXCL_START 1039 return CeedError(ceed, CEED_ERROR_INCOMPLETE, 1040 "At least one non-collocated basis is required " 1041 "or the number of quadrature points must be set"); 1042 // LCOV_EXCL_STOP 1043 } 1044 1045 // Flag as immutable and ready 1046 op->is_interface_setup = true; 1047 if (op->qf && op->qf != CEED_QFUNCTION_NONE) 1048 // LCOV_EXCL_START 1049 op->qf->is_immutable = true; 1050 // LCOV_EXCL_STOP 1051 if (op->dqf && op->dqf != CEED_QFUNCTION_NONE) 1052 // LCOV_EXCL_START 1053 op->dqf->is_immutable = true; 1054 // LCOV_EXCL_STOP 1055 if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE) 1056 // LCOV_EXCL_START 1057 op->dqfT->is_immutable = true; 1058 // LCOV_EXCL_STOP 1059 return CEED_ERROR_SUCCESS; 1060 } 1061 1062 /** 1063 @brief Get vector lengths for the active input and/or output vectors of a CeedOperator. 1064 Note: Lengths of -1 indicate that the CeedOperator does not have an 1065 active input and/or output. 1066 1067 @param[in] op CeedOperator 1068 @param[out] input_size Variable to store active input vector length, or NULL 1069 @param[out] output_size Variable to store active output vector length, or NULL 1070 1071 @return An error code: 0 - success, otherwise - failure 1072 1073 @ref User 1074 **/ 1075 int CeedOperatorGetActiveVectorLengths(CeedOperator op, CeedSize *input_size, 1076 CeedSize *output_size) { 1077 int ierr; 1078 bool is_composite; 1079 1080 if (input_size) *input_size = op->input_size; 1081 if (output_size) *output_size = op->output_size; 1082 1083 ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1084 if (is_composite && (op->input_size == -1 || op->output_size == -1)) { 1085 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1086 CeedSize sub_input_size, sub_output_size; 1087 ierr = CeedOperatorGetActiveVectorLengths(op->sub_operators[i], 1088 &sub_input_size, &sub_output_size); CeedChk(ierr); 1089 if (op->input_size == -1) op->input_size = sub_input_size; 1090 if (op->output_size == -1) op->output_size = sub_output_size; 1091 // Note, a size of -1 means no active vector restriction set, so no incompatibility 1092 if ((sub_input_size != -1 && sub_input_size != op->input_size) || 1093 (sub_output_size != -1 && sub_output_size != op->output_size)) 1094 // LCOV_EXCL_START 1095 return CeedError(op->ceed, CEED_ERROR_MAJOR, 1096 "Sub-operators must have compatible dimensions; " 1097 "composite operator of shape (%td, %td) not compatible with " 1098 "sub-operator of shape (%td, %td)", 1099 op->input_size, op->output_size, input_size, output_size); 1100 // LCOV_EXCL_STOP 1101 } 1102 } 1103 1104 return CEED_ERROR_SUCCESS; 1105 } 1106 1107 /** 1108 @brief Set reuse of CeedQFunction data in CeedOperatorLinearAssemble* functions. 1109 When `reuse_assembly_data = false` (default), the CeedQFunction associated 1110 with this CeedOperator is re-assembled every time a `CeedOperatorLinearAssemble*` 1111 function is called. 1112 When `reuse_assembly_data = true`, the CeedQFunction associated with 1113 this CeedOperator is reused between calls to 1114 `CeedOperatorSetQFunctionAssemblyDataUpdated`. 1115 1116 @param[in] op CeedOperator 1117 @param[in] reuse_assembly_data Boolean flag setting assembly data reuse 1118 1119 @return An error code: 0 - success, otherwise - failure 1120 1121 @ref Advanced 1122 **/ 1123 int CeedOperatorSetQFunctionAssemblyReuse(CeedOperator op, 1124 bool reuse_assembly_data) { 1125 int ierr; 1126 bool is_composite; 1127 1128 ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1129 if (is_composite) { 1130 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1131 ierr = CeedOperatorSetQFunctionAssemblyReuse(op->sub_operators[i], 1132 reuse_assembly_data); CeedChk(ierr); 1133 } 1134 } else { 1135 ierr = CeedQFunctionAssemblyDataSetReuse(op->qf_assembled, reuse_assembly_data); 1136 CeedChk(ierr); 1137 } 1138 1139 return CEED_ERROR_SUCCESS; 1140 } 1141 1142 /** 1143 @brief Mark CeedQFunction data as updated and the CeedQFunction as requiring re-assembly. 1144 1145 @param[in] op CeedOperator 1146 @param[in] needs_data_update Boolean flag setting assembly data reuse 1147 1148 @return An error code: 0 - success, otherwise - failure 1149 1150 @ref Advanced 1151 **/ 1152 int CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(CeedOperator op, 1153 bool needs_data_update) { 1154 int ierr; 1155 bool is_composite; 1156 1157 ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1158 if (is_composite) { 1159 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1160 ierr = CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(op->sub_operators[i], 1161 needs_data_update); CeedChk(ierr); 1162 } 1163 } else { 1164 ierr = CeedQFunctionAssemblyDataSetUpdateNeeded(op->qf_assembled, 1165 needs_data_update); 1166 CeedChk(ierr); 1167 } 1168 1169 return CEED_ERROR_SUCCESS; 1170 } 1171 1172 /** 1173 @brief Set the number of quadrature points associated with a CeedOperator. 1174 This should be used when creating a CeedOperator where every 1175 field has a collocated basis. This function cannot be used for 1176 composite CeedOperators. 1177 1178 @param op CeedOperator 1179 @param num_qpts Number of quadrature points to set 1180 1181 @return An error code: 0 - success, otherwise - failure 1182 1183 @ref Advanced 1184 **/ 1185 int CeedOperatorSetNumQuadraturePoints(CeedOperator op, CeedInt num_qpts) { 1186 if (op->is_composite) 1187 // LCOV_EXCL_START 1188 return CeedError(op->ceed, CEED_ERROR_MINOR, 1189 "Not defined for composite operator"); 1190 // LCOV_EXCL_STOP 1191 if (op->num_qpts) 1192 // LCOV_EXCL_START 1193 return CeedError(op->ceed, CEED_ERROR_MINOR, 1194 "Number of quadrature points already defined"); 1195 // LCOV_EXCL_STOP 1196 if (op->is_immutable) 1197 // LCOV_EXCL_START 1198 return CeedError(op->ceed, CEED_ERROR_MAJOR, 1199 "Operator cannot be changed after set as immutable"); 1200 // LCOV_EXCL_STOP 1201 1202 op->num_qpts = num_qpts; 1203 return CEED_ERROR_SUCCESS; 1204 } 1205 1206 /** 1207 @brief Set name of CeedOperator for CeedOperatorView output 1208 1209 @param op CeedOperator 1210 @param name Name to set, or NULL to remove previously set name 1211 1212 @return An error code: 0 - success, otherwise - failure 1213 1214 @ref User 1215 **/ 1216 int CeedOperatorSetName(CeedOperator op, const char *name) { 1217 int ierr; 1218 char *name_copy; 1219 size_t name_len = name ? strlen(name) : 0; 1220 1221 ierr = CeedFree(&op->name); CeedChk(ierr); 1222 if (name_len > 0) { 1223 ierr = CeedCalloc(name_len + 1, &name_copy); CeedChk(ierr); 1224 memcpy(name_copy, name, name_len); 1225 op->name = name_copy; 1226 } 1227 1228 return CEED_ERROR_SUCCESS; 1229 } 1230 1231 /** 1232 @brief View a CeedOperator 1233 1234 @param[in] op CeedOperator to view 1235 @param[in] stream Stream to write; typically stdout/stderr or a file 1236 1237 @return Error code: 0 - success, otherwise - failure 1238 1239 @ref User 1240 **/ 1241 int CeedOperatorView(CeedOperator op, FILE *stream) { 1242 int ierr; 1243 bool has_name = op->name; 1244 1245 if (op->is_composite) { 1246 fprintf(stream, "Composite CeedOperator%s%s\n", 1247 has_name ? " - " : "", has_name ? op->name : ""); 1248 1249 for (CeedInt i=0; i<op->num_suboperators; i++) { 1250 has_name = op->sub_operators[i]->name; 1251 fprintf(stream, " SubOperator %" CeedInt_FMT "%s%s:\n", i, 1252 has_name ? " - " : "", 1253 has_name ? op->sub_operators[i]->name : ""); 1254 ierr = CeedOperatorSingleView(op->sub_operators[i], 1, stream); 1255 CeedChk(ierr); 1256 } 1257 } else { 1258 fprintf(stream, "CeedOperator%s%s\n", 1259 has_name ? " - " : "", has_name ? op->name : ""); 1260 ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr); 1261 } 1262 return CEED_ERROR_SUCCESS; 1263 } 1264 1265 /** 1266 @brief Get the Ceed associated with a CeedOperator 1267 1268 @param op CeedOperator 1269 @param[out] ceed Variable to store Ceed 1270 1271 @return An error code: 0 - success, otherwise - failure 1272 1273 @ref Advanced 1274 **/ 1275 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) { 1276 *ceed = op->ceed; 1277 return CEED_ERROR_SUCCESS; 1278 } 1279 1280 /** 1281 @brief Get the number of elements associated with a CeedOperator 1282 1283 @param op CeedOperator 1284 @param[out] num_elem Variable to store number of elements 1285 1286 @return An error code: 0 - success, otherwise - failure 1287 1288 @ref Advanced 1289 **/ 1290 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) { 1291 if (op->is_composite) 1292 // LCOV_EXCL_START 1293 return CeedError(op->ceed, CEED_ERROR_MINOR, 1294 "Not defined for composite operator"); 1295 // LCOV_EXCL_STOP 1296 1297 *num_elem = op->num_elem; 1298 return CEED_ERROR_SUCCESS; 1299 } 1300 1301 /** 1302 @brief Get the number of quadrature points associated with a CeedOperator 1303 1304 @param op CeedOperator 1305 @param[out] num_qpts Variable to store vector number of quadrature points 1306 1307 @return An error code: 0 - success, otherwise - failure 1308 1309 @ref Advanced 1310 **/ 1311 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) { 1312 if (op->is_composite) 1313 // LCOV_EXCL_START 1314 return CeedError(op->ceed, CEED_ERROR_MINOR, 1315 "Not defined for composite operator"); 1316 // LCOV_EXCL_STOP 1317 1318 *num_qpts = op->num_qpts; 1319 return CEED_ERROR_SUCCESS; 1320 } 1321 1322 /** 1323 @brief Estimate number of FLOPs required to apply CeedOperator on the active vector 1324 1325 @param op Operator to estimate FLOPs for 1326 @param flops Address of variable to hold FLOPs estimate 1327 1328 @ref Backend 1329 **/ 1330 int CeedOperatorGetFlopsEstimate(CeedOperator op, CeedSize *flops) { 1331 int ierr; 1332 bool is_composite; 1333 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1334 1335 *flops = 0; 1336 ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1337 if (is_composite) { 1338 CeedInt num_suboperators; 1339 ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1340 CeedOperator *sub_operators; 1341 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1342 1343 // FLOPs for each suboperator 1344 for (CeedInt i = 0; i < num_suboperators; i++) { 1345 CeedSize suboperator_flops; 1346 ierr = CeedOperatorGetFlopsEstimate(sub_operators[i], &suboperator_flops); 1347 CeedChk(ierr); 1348 *flops += suboperator_flops; 1349 } 1350 } else { 1351 CeedInt num_input_fields, num_output_fields; 1352 CeedOperatorField *input_fields, *output_fields; 1353 1354 ierr = CeedOperatorGetFields(op, &num_input_fields, &input_fields, 1355 &num_output_fields, &output_fields); CeedChk(ierr); 1356 1357 CeedInt num_elem = 0; 1358 ierr = CeedOperatorGetNumElements(op, &num_elem); CeedChk(ierr); 1359 // Input FLOPs 1360 for (CeedInt i = 0; i < num_input_fields; i++) { 1361 if (input_fields[i]->vec == CEED_VECTOR_ACTIVE) { 1362 CeedSize restr_flops, basis_flops; 1363 1364 ierr = CeedElemRestrictionGetFlopsEstimate(input_fields[i]->elem_restr, 1365 CEED_NOTRANSPOSE, &restr_flops); CeedChk(ierr); 1366 *flops += restr_flops; 1367 ierr = CeedBasisGetFlopsEstimate(input_fields[i]->basis, CEED_NOTRANSPOSE, 1368 op->qf->input_fields[i]->eval_mode, &basis_flops); CeedChk(ierr); 1369 *flops += basis_flops * num_elem; 1370 } 1371 } 1372 // QF FLOPs 1373 CeedInt num_qpts; 1374 CeedSize qf_flops; 1375 ierr = CeedOperatorGetNumQuadraturePoints(op, &num_qpts); CeedChk(ierr); 1376 ierr = CeedQFunctionGetFlopsEstimate(op->qf, &qf_flops); CeedChk(ierr); 1377 *flops += num_elem * num_qpts * qf_flops; 1378 // Output FLOPs 1379 for (CeedInt i = 0; i < num_output_fields; i++) { 1380 if (output_fields[i]->vec == CEED_VECTOR_ACTIVE) { 1381 CeedSize restr_flops, basis_flops; 1382 1383 ierr = CeedElemRestrictionGetFlopsEstimate(output_fields[i]->elem_restr, 1384 CEED_TRANSPOSE, &restr_flops); CeedChk(ierr); 1385 *flops += restr_flops; 1386 ierr = CeedBasisGetFlopsEstimate(output_fields[i]->basis, CEED_TRANSPOSE, 1387 op->qf->output_fields[i]->eval_mode, &basis_flops); CeedChk(ierr); 1388 *flops += basis_flops * num_elem; 1389 } 1390 } 1391 } 1392 1393 return CEED_ERROR_SUCCESS; 1394 } 1395 1396 /** 1397 @brief Get label for a registered QFunctionContext field, or `NULL` if no 1398 field has been registered with this `field_name`. 1399 1400 @param[in] op CeedOperator 1401 @param[in] field_name Name of field to retrieve label 1402 @param[out] field_label Variable to field label 1403 1404 @return An error code: 0 - success, otherwise - failure 1405 1406 @ref User 1407 **/ 1408 int CeedOperatorContextGetFieldLabel(CeedOperator op, 1409 const char *field_name, 1410 CeedContextFieldLabel *field_label) { 1411 int ierr; 1412 1413 bool is_composite; 1414 ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1415 if (is_composite) { 1416 // Check if composite label already created 1417 for (CeedInt i=0; i<op->num_context_labels; i++) { 1418 if (!strcmp(op->context_labels[i]->name, field_name)) { 1419 *field_label = op->context_labels[i]; 1420 return CEED_ERROR_SUCCESS; 1421 } 1422 } 1423 1424 // Create composite label if needed 1425 CeedInt num_sub; 1426 CeedOperator *sub_operators; 1427 CeedContextFieldLabel new_field_label; 1428 1429 ierr = CeedCalloc(1, &new_field_label); CeedChk(ierr); 1430 ierr = CeedOperatorGetNumSub(op, &num_sub); CeedChk(ierr); 1431 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1432 ierr = CeedCalloc(num_sub, &new_field_label->sub_labels); CeedChk(ierr); 1433 new_field_label->num_sub_labels = num_sub; 1434 1435 bool label_found = false; 1436 for (CeedInt i=0; i<num_sub; i++) { 1437 if (sub_operators[i]->qf->ctx) { 1438 CeedContextFieldLabel new_field_label_i; 1439 ierr = CeedQFunctionContextGetFieldLabel(sub_operators[i]->qf->ctx, field_name, 1440 &new_field_label_i); CeedChk(ierr); 1441 if (new_field_label_i) { 1442 label_found = true; 1443 new_field_label->sub_labels[i] = new_field_label_i; 1444 new_field_label->name = new_field_label_i->name; 1445 new_field_label->description = new_field_label_i->description; 1446 if (new_field_label->type && 1447 new_field_label->type != new_field_label_i->type) { 1448 // LCOV_EXCL_START 1449 ierr = CeedFree(&new_field_label); CeedChk(ierr); 1450 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 1451 "Incompatible field types on sub-operator contexts. " 1452 "%s != %s", 1453 CeedContextFieldTypes[new_field_label->type], 1454 CeedContextFieldTypes[new_field_label_i->type]); 1455 // LCOV_EXCL_STOP 1456 } else { 1457 new_field_label->type = new_field_label_i->type; 1458 } 1459 if (new_field_label->num_values != 0 && 1460 new_field_label->num_values != new_field_label_i->num_values) { 1461 // LCOV_EXCL_START 1462 ierr = CeedFree(&new_field_label); CeedChk(ierr); 1463 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 1464 "Incompatible field number of values on sub-operator" 1465 " contexts. %ld != %ld", 1466 new_field_label->num_values, new_field_label_i->num_values); 1467 // LCOV_EXCL_STOP 1468 } else { 1469 new_field_label->num_values = new_field_label_i->num_values; 1470 } 1471 } 1472 } 1473 } 1474 if (!label_found) { 1475 // LCOV_EXCL_START 1476 ierr = CeedFree(&new_field_label->sub_labels); CeedChk(ierr); 1477 ierr = CeedFree(&new_field_label); CeedChk(ierr); 1478 *field_label = NULL; 1479 // LCOV_EXCL_STOP 1480 } else { 1481 // Move new composite label to operator 1482 if (op->num_context_labels == 0) { 1483 ierr = CeedCalloc(1, &op->context_labels); CeedChk(ierr); 1484 op->max_context_labels = 1; 1485 } else if (op->num_context_labels == op->max_context_labels) { 1486 ierr = CeedRealloc(2*op->num_context_labels, &op->context_labels); 1487 CeedChk(ierr); 1488 op->max_context_labels *= 2; 1489 } 1490 op->context_labels[op->num_context_labels] = new_field_label; 1491 *field_label = new_field_label; 1492 op->num_context_labels++; 1493 } 1494 1495 return CEED_ERROR_SUCCESS; 1496 } else { 1497 return CeedQFunctionContextGetFieldLabel(op->qf->ctx, field_name, field_label); 1498 } 1499 } 1500 1501 /** 1502 @brief Set QFunctionContext field holding a double precision value. 1503 For composite operators, the value is set in all 1504 sub-operator QFunctionContexts that have a matching `field_name`. 1505 1506 @param op CeedOperator 1507 @param field_label Label of field to register 1508 @param values Values to set 1509 1510 @return An error code: 0 - success, otherwise - failure 1511 1512 @ref User 1513 **/ 1514 int CeedOperatorContextSetDouble(CeedOperator op, 1515 CeedContextFieldLabel field_label, 1516 double *values) { 1517 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, 1518 values); 1519 } 1520 1521 /** 1522 @brief Set QFunctionContext field holding an int32 value. 1523 For composite operators, the value is set in all 1524 sub-operator QFunctionContexts that have a matching `field_name`. 1525 1526 @param op CeedOperator 1527 @param field_label Label of field to set 1528 @param values Values to set 1529 1530 @return An error code: 0 - success, otherwise - failure 1531 1532 @ref User 1533 **/ 1534 int CeedOperatorContextSetInt32(CeedOperator op, 1535 CeedContextFieldLabel field_label, 1536 int *values) { 1537 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_INT32, 1538 values); 1539 } 1540 1541 /** 1542 @brief Apply CeedOperator to a vector 1543 1544 This computes the action of the operator on the specified (active) input, 1545 yielding its (active) output. All inputs and outputs must be specified using 1546 CeedOperatorSetField(). 1547 1548 Note: Calling this function asserts that setup is complete 1549 and sets the CeedOperator as immutable. 1550 1551 @param op CeedOperator to apply 1552 @param[in] in CeedVector containing input state or @ref CEED_VECTOR_NONE if 1553 there are no active inputs 1554 @param[out] out CeedVector to store result of applying operator (must be 1555 distinct from @a in) or @ref CEED_VECTOR_NONE if there are no 1556 active outputs 1557 @param request Address of CeedRequest for non-blocking completion, else 1558 @ref CEED_REQUEST_IMMEDIATE 1559 1560 @return An error code: 0 - success, otherwise - failure 1561 1562 @ref User 1563 **/ 1564 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, 1565 CeedRequest *request) { 1566 int ierr; 1567 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1568 1569 if (op->num_elem) { 1570 // Standard Operator 1571 if (op->Apply) { 1572 ierr = op->Apply(op, in, out, request); CeedChk(ierr); 1573 } else { 1574 // Zero all output vectors 1575 CeedQFunction qf = op->qf; 1576 for (CeedInt i=0; i<qf->num_output_fields; i++) { 1577 CeedVector vec = op->output_fields[i]->vec; 1578 if (vec == CEED_VECTOR_ACTIVE) 1579 vec = out; 1580 if (vec != CEED_VECTOR_NONE) { 1581 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 1582 } 1583 } 1584 // Apply 1585 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 1586 } 1587 } else if (op->is_composite) { 1588 // Composite Operator 1589 if (op->ApplyComposite) { 1590 ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr); 1591 } else { 1592 CeedInt num_suboperators; 1593 ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1594 CeedOperator *sub_operators; 1595 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1596 1597 // Zero all output vectors 1598 if (out != CEED_VECTOR_NONE) { 1599 ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr); 1600 } 1601 for (CeedInt i=0; i<num_suboperators; i++) { 1602 for (CeedInt j=0; j<sub_operators[i]->qf->num_output_fields; j++) { 1603 CeedVector vec = sub_operators[i]->output_fields[j]->vec; 1604 if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) { 1605 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 1606 } 1607 } 1608 } 1609 // Apply 1610 for (CeedInt i=0; i<op->num_suboperators; i++) { 1611 ierr = CeedOperatorApplyAdd(op->sub_operators[i], in, out, request); 1612 CeedChk(ierr); 1613 } 1614 } 1615 } 1616 return CEED_ERROR_SUCCESS; 1617 } 1618 1619 /** 1620 @brief Apply CeedOperator to a vector and add result to output vector 1621 1622 This computes the action of the operator on the specified (active) input, 1623 yielding its (active) output. All inputs and outputs must be specified using 1624 CeedOperatorSetField(). 1625 1626 @param op CeedOperator to apply 1627 @param[in] in CeedVector containing input state or NULL if there are no 1628 active inputs 1629 @param[out] out CeedVector to sum in result of applying operator (must be 1630 distinct from @a in) or NULL if there are no active outputs 1631 @param request Address of CeedRequest for non-blocking completion, else 1632 @ref CEED_REQUEST_IMMEDIATE 1633 1634 @return An error code: 0 - success, otherwise - failure 1635 1636 @ref User 1637 **/ 1638 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, 1639 CeedRequest *request) { 1640 int ierr; 1641 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1642 1643 if (op->num_elem) { 1644 // Standard Operator 1645 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 1646 } else if (op->is_composite) { 1647 // Composite Operator 1648 if (op->ApplyAddComposite) { 1649 ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr); 1650 } else { 1651 CeedInt num_suboperators; 1652 ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1653 CeedOperator *sub_operators; 1654 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1655 1656 for (CeedInt i=0; i<num_suboperators; i++) { 1657 ierr = CeedOperatorApplyAdd(sub_operators[i], in, out, request); 1658 CeedChk(ierr); 1659 } 1660 } 1661 } 1662 return CEED_ERROR_SUCCESS; 1663 } 1664 1665 /** 1666 @brief Destroy a CeedOperator 1667 1668 @param op CeedOperator to destroy 1669 1670 @return An error code: 0 - success, otherwise - failure 1671 1672 @ref User 1673 **/ 1674 int CeedOperatorDestroy(CeedOperator *op) { 1675 int ierr; 1676 1677 if (!*op || --(*op)->ref_count > 0) return CEED_ERROR_SUCCESS; 1678 if ((*op)->Destroy) { 1679 ierr = (*op)->Destroy(*op); CeedChk(ierr); 1680 } 1681 ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr); 1682 // Free fields 1683 for (CeedInt i=0; i<(*op)->num_fields; i++) 1684 if ((*op)->input_fields[i]) { 1685 if ((*op)->input_fields[i]->elem_restr != CEED_ELEMRESTRICTION_NONE) { 1686 ierr = CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_restr); 1687 CeedChk(ierr); 1688 } 1689 if ((*op)->input_fields[i]->basis != CEED_BASIS_COLLOCATED) { 1690 ierr = CeedBasisDestroy(&(*op)->input_fields[i]->basis); CeedChk(ierr); 1691 } 1692 if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE && 1693 (*op)->input_fields[i]->vec != CEED_VECTOR_NONE ) { 1694 ierr = CeedVectorDestroy(&(*op)->input_fields[i]->vec); CeedChk(ierr); 1695 } 1696 ierr = CeedFree(&(*op)->input_fields[i]->field_name); CeedChk(ierr); 1697 ierr = CeedFree(&(*op)->input_fields[i]); CeedChk(ierr); 1698 } 1699 for (CeedInt i=0; i<(*op)->num_fields; i++) 1700 if ((*op)->output_fields[i]) { 1701 ierr = CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_restr); 1702 CeedChk(ierr); 1703 if ((*op)->output_fields[i]->basis != CEED_BASIS_COLLOCATED) { 1704 ierr = CeedBasisDestroy(&(*op)->output_fields[i]->basis); CeedChk(ierr); 1705 } 1706 if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE && 1707 (*op)->output_fields[i]->vec != CEED_VECTOR_NONE ) { 1708 ierr = CeedVectorDestroy(&(*op)->output_fields[i]->vec); CeedChk(ierr); 1709 } 1710 ierr = CeedFree(&(*op)->output_fields[i]->field_name); CeedChk(ierr); 1711 ierr = CeedFree(&(*op)->output_fields[i]); CeedChk(ierr); 1712 } 1713 // Destroy sub_operators 1714 for (CeedInt i=0; i<(*op)->num_suboperators; i++) 1715 if ((*op)->sub_operators[i]) { 1716 ierr = CeedOperatorDestroy(&(*op)->sub_operators[i]); CeedChk(ierr); 1717 } 1718 ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr); 1719 ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr); 1720 ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr); 1721 // Destroy any composite labels 1722 for (CeedInt i=0; i<(*op)->num_context_labels; i++) { 1723 ierr = CeedFree(&(*op)->context_labels[i]->sub_labels); CeedChk(ierr); 1724 ierr = CeedFree(&(*op)->context_labels[i]); CeedChk(ierr); 1725 } 1726 ierr = CeedFree(&(*op)->context_labels); CeedChk(ierr); 1727 1728 // Destroy fallback 1729 ierr = CeedOperatorDestroy(&(*op)->op_fallback); CeedChk(ierr); 1730 1731 // Destroy assembly data 1732 ierr = CeedQFunctionAssemblyDataDestroy(&(*op)->qf_assembled); CeedChk(ierr); 1733 ierr = CeedOperatorAssemblyDataDestroy(&(*op)->op_assembled); CeedChk(ierr); 1734 1735 ierr = CeedFree(&(*op)->input_fields); CeedChk(ierr); 1736 ierr = CeedFree(&(*op)->output_fields); CeedChk(ierr); 1737 ierr = CeedFree(&(*op)->sub_operators); CeedChk(ierr); 1738 ierr = CeedFree(&(*op)->name); CeedChk(ierr); 1739 ierr = CeedFree(op); CeedChk(ierr); 1740 return CEED_ERROR_SUCCESS; 1741 } 1742 1743 /// @} 1744