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)->is_composite = true; 649 ierr = CeedCalloc(CEED_COMPOSITE_MAX, &(*op)->sub_operators); CeedChk(ierr); 650 (*op)->input_size = -1; 651 (*op)->output_size = -1; 652 653 if (ceed->CompositeOperatorCreate) { 654 ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr); 655 } 656 return CEED_ERROR_SUCCESS; 657 } 658 659 /** 660 @brief Copy the pointer to a CeedOperator. Both pointers should 661 be destroyed with `CeedOperatorDestroy()`; 662 Note: If `*op_copy` is non-NULL, then it is assumed that 663 `*op_copy` is a pointer to a CeedOperator. This 664 CeedOperator will be destroyed if `*op_copy` is the only 665 reference to this CeedOperator. 666 667 @param op CeedOperator to copy reference to 668 @param[out] op_copy Variable to store copied reference 669 670 @return An error code: 0 - success, otherwise - failure 671 672 @ref User 673 **/ 674 int CeedOperatorReferenceCopy(CeedOperator op, CeedOperator *op_copy) { 675 int ierr; 676 677 ierr = CeedOperatorReference(op); CeedChk(ierr); 678 ierr = CeedOperatorDestroy(op_copy); CeedChk(ierr); 679 *op_copy = op; 680 return CEED_ERROR_SUCCESS; 681 } 682 683 /** 684 @brief Provide a field to a CeedOperator for use by its CeedQFunction 685 686 This function is used to specify both active and passive fields to a 687 CeedOperator. For passive fields, a vector @arg v must be provided. Passive 688 fields can inputs or outputs (updated in-place when operator is applied). 689 690 Active fields must be specified using this function, but their data (in a 691 CeedVector) is passed in CeedOperatorApply(). There can be at most one active 692 input CeedVector and at most one active output CeedVector passed to 693 CeedOperatorApply(). 694 695 @param op CeedOperator on which to provide the field 696 @param field_name Name of the field (to be matched with the name used by 697 CeedQFunction) 698 @param r CeedElemRestriction 699 @param b CeedBasis in which the field resides or @ref CEED_BASIS_COLLOCATED 700 if collocated with quadrature points 701 @param v CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE 702 if field is active or @ref CEED_VECTOR_NONE if using 703 @ref CEED_EVAL_WEIGHT in the QFunction 704 705 @return An error code: 0 - success, otherwise - failure 706 707 @ref User 708 **/ 709 int CeedOperatorSetField(CeedOperator op, const char *field_name, 710 CeedElemRestriction r, CeedBasis b, CeedVector v) { 711 int ierr; 712 if (op->is_composite) 713 // LCOV_EXCL_START 714 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 715 "Cannot add field to composite operator."); 716 // LCOV_EXCL_STOP 717 if (op->is_immutable) 718 // LCOV_EXCL_START 719 return CeedError(op->ceed, CEED_ERROR_MAJOR, 720 "Operator cannot be changed after set as immutable"); 721 // LCOV_EXCL_STOP 722 if (!r) 723 // LCOV_EXCL_START 724 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 725 "ElemRestriction r for field \"%s\" must be non-NULL.", 726 field_name); 727 // LCOV_EXCL_STOP 728 if (!b) 729 // LCOV_EXCL_START 730 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 731 "Basis b for field \"%s\" must be non-NULL.", 732 field_name); 733 // LCOV_EXCL_STOP 734 if (!v) 735 // LCOV_EXCL_START 736 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 737 "Vector v for field \"%s\" must be non-NULL.", 738 field_name); 739 // LCOV_EXCL_STOP 740 741 CeedInt num_elem; 742 ierr = CeedElemRestrictionGetNumElements(r, &num_elem); CeedChk(ierr); 743 if (r != CEED_ELEMRESTRICTION_NONE && op->has_restriction && 744 op->num_elem != num_elem) 745 // LCOV_EXCL_START 746 return CeedError(op->ceed, CEED_ERROR_DIMENSION, 747 "ElemRestriction with %" CeedInt_FMT " elements incompatible with prior " 748 CeedInt_FMT " elements", num_elem, op->num_elem); 749 // LCOV_EXCL_STOP 750 751 CeedInt num_qpts = 0; 752 if (b != CEED_BASIS_COLLOCATED) { 753 ierr = CeedBasisGetNumQuadraturePoints(b, &num_qpts); CeedChk(ierr); 754 if (op->num_qpts && op->num_qpts != num_qpts) 755 // LCOV_EXCL_START 756 return CeedError(op->ceed, CEED_ERROR_DIMENSION, 757 "Basis with %" CeedInt_FMT " quadrature points " 758 "incompatible with prior %" CeedInt_FMT " points", num_qpts, 759 op->num_qpts); 760 // LCOV_EXCL_STOP 761 } 762 CeedQFunctionField qf_field; 763 CeedOperatorField *op_field; 764 bool is_input = true; 765 for (CeedInt i=0; i<op->qf->num_input_fields; i++) { 766 if (!strcmp(field_name, (*op->qf->input_fields[i]).field_name)) { 767 qf_field = op->qf->input_fields[i]; 768 op_field = &op->input_fields[i]; 769 goto found; 770 } 771 } 772 is_input = false; 773 for (CeedInt i=0; i<op->qf->num_output_fields; i++) { 774 if (!strcmp(field_name, (*op->qf->output_fields[i]).field_name)) { 775 qf_field = op->qf->output_fields[i]; 776 op_field = &op->output_fields[i]; 777 goto found; 778 } 779 } 780 // LCOV_EXCL_START 781 return CeedError(op->ceed, CEED_ERROR_INCOMPLETE, 782 "QFunction has no knowledge of field '%s'", 783 field_name); 784 // LCOV_EXCL_STOP 785 found: 786 ierr = CeedOperatorCheckField(op->ceed, qf_field, r, b); CeedChk(ierr); 787 ierr = CeedCalloc(1, op_field); CeedChk(ierr); 788 789 if (v == CEED_VECTOR_ACTIVE) { 790 CeedSize l_size; 791 ierr = CeedElemRestrictionGetLVectorSize(r, &l_size); CeedChk(ierr); 792 if (is_input) { 793 if (op->input_size == -1) op->input_size = l_size; 794 if (l_size != op->input_size) 795 // LCOV_EXCL_START 796 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 797 "LVector size %td does not match previous size %td", 798 l_size, op->input_size); 799 // LCOV_EXCL_STOP 800 } else { 801 if (op->output_size == -1) op->output_size = l_size; 802 if (l_size != op->output_size) 803 // LCOV_EXCL_START 804 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 805 "LVector size %td does not match previous size %td", 806 l_size, op->output_size); 807 // LCOV_EXCL_STOP 808 } 809 } 810 811 (*op_field)->vec = v; 812 if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) { 813 ierr = CeedVectorReference(v); CeedChk(ierr); 814 } 815 816 (*op_field)->elem_restr = r; 817 ierr = CeedElemRestrictionReference(r); CeedChk(ierr); 818 if (r != CEED_ELEMRESTRICTION_NONE) { 819 op->num_elem = num_elem; 820 op->has_restriction = true; // Restriction set, but num_elem may be 0 821 } 822 823 (*op_field)->basis = b; 824 if (b != CEED_BASIS_COLLOCATED) { 825 if (!op->num_qpts) { 826 ierr = CeedOperatorSetNumQuadraturePoints(op, num_qpts); CeedChk(ierr); 827 } 828 ierr = CeedBasisReference(b); CeedChk(ierr); 829 } 830 831 op->num_fields += 1; 832 ierr = CeedStringAllocCopy(field_name, (char **)&(*op_field)->field_name); 833 CeedChk(ierr); 834 return CEED_ERROR_SUCCESS; 835 } 836 837 /** 838 @brief Get the CeedOperatorFields of a CeedOperator 839 840 Note: Calling this function asserts that setup is complete 841 and sets the CeedOperator as immutable. 842 843 @param op CeedOperator 844 @param[out] num_input_fields Variable to store number of input fields 845 @param[out] input_fields Variable to store input_fields 846 @param[out] num_output_fields Variable to store number of output fields 847 @param[out] output_fields Variable to store output_fields 848 849 @return An error code: 0 - success, otherwise - failure 850 851 @ref Advanced 852 **/ 853 int CeedOperatorGetFields(CeedOperator op, CeedInt *num_input_fields, 854 CeedOperatorField **input_fields, 855 CeedInt *num_output_fields, 856 CeedOperatorField **output_fields) { 857 int ierr; 858 859 if (op->is_composite) 860 // LCOV_EXCL_START 861 return CeedError(op->ceed, CEED_ERROR_MINOR, 862 "Not defined for composite operator"); 863 // LCOV_EXCL_STOP 864 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 865 866 if (num_input_fields) *num_input_fields = op->qf->num_input_fields; 867 if (input_fields) *input_fields = op->input_fields; 868 if (num_output_fields) *num_output_fields = op->qf->num_output_fields; 869 if (output_fields) *output_fields = op->output_fields; 870 return CEED_ERROR_SUCCESS; 871 } 872 873 /** 874 @brief Get the name of a CeedOperatorField 875 876 @param op_field CeedOperatorField 877 @param[out] field_name Variable to store the field name 878 879 @return An error code: 0 - success, otherwise - failure 880 881 @ref Advanced 882 **/ 883 int CeedOperatorFieldGetName(CeedOperatorField op_field, char **field_name) { 884 *field_name = (char *)op_field->field_name; 885 return CEED_ERROR_SUCCESS; 886 } 887 888 /** 889 @brief Get the CeedElemRestriction of a CeedOperatorField 890 891 @param op_field CeedOperatorField 892 @param[out] rstr Variable to store CeedElemRestriction 893 894 @return An error code: 0 - success, otherwise - failure 895 896 @ref Advanced 897 **/ 898 int CeedOperatorFieldGetElemRestriction(CeedOperatorField op_field, 899 CeedElemRestriction *rstr) { 900 *rstr = op_field->elem_restr; 901 return CEED_ERROR_SUCCESS; 902 } 903 904 /** 905 @brief Get the CeedBasis of a CeedOperatorField 906 907 @param op_field CeedOperatorField 908 @param[out] basis Variable to store CeedBasis 909 910 @return An error code: 0 - success, otherwise - failure 911 912 @ref Advanced 913 **/ 914 int CeedOperatorFieldGetBasis(CeedOperatorField op_field, CeedBasis *basis) { 915 *basis = op_field->basis; 916 return CEED_ERROR_SUCCESS; 917 } 918 919 /** 920 @brief Get the CeedVector of a CeedOperatorField 921 922 @param op_field CeedOperatorField 923 @param[out] vec Variable to store CeedVector 924 925 @return An error code: 0 - success, otherwise - failure 926 927 @ref Advanced 928 **/ 929 int CeedOperatorFieldGetVector(CeedOperatorField op_field, CeedVector *vec) { 930 *vec = op_field->vec; 931 return CEED_ERROR_SUCCESS; 932 } 933 934 /** 935 @brief Add a sub-operator to a composite CeedOperator 936 937 @param[out] composite_op Composite CeedOperator 938 @param sub_op Sub-operator CeedOperator 939 940 @return An error code: 0 - success, otherwise - failure 941 942 @ref User 943 */ 944 int CeedCompositeOperatorAddSub(CeedOperator composite_op, 945 CeedOperator sub_op) { 946 int ierr; 947 948 if (!composite_op->is_composite) 949 // LCOV_EXCL_START 950 return CeedError(composite_op->ceed, CEED_ERROR_MINOR, 951 "CeedOperator is not a composite operator"); 952 // LCOV_EXCL_STOP 953 954 if (composite_op->num_suboperators == CEED_COMPOSITE_MAX) 955 // LCOV_EXCL_START 956 return CeedError(composite_op->ceed, CEED_ERROR_UNSUPPORTED, 957 "Cannot add additional sub-operators"); 958 // LCOV_EXCL_STOP 959 if (composite_op->is_immutable) 960 // LCOV_EXCL_START 961 return CeedError(composite_op->ceed, CEED_ERROR_MAJOR, 962 "Operator cannot be changed after set as immutable"); 963 // LCOV_EXCL_STOP 964 965 { 966 CeedSize input_size, output_size; 967 ierr = CeedOperatorGetActiveVectorLengths(sub_op, &input_size, &output_size); 968 CeedChk(ierr); 969 if (composite_op->input_size == -1) composite_op->input_size = input_size; 970 if (composite_op->output_size == -1) composite_op->output_size = output_size; 971 // Note, a size of -1 means no active vector restriction set, so no incompatibility 972 if ((input_size != -1 && input_size != composite_op->input_size) || 973 (output_size != -1 && output_size != composite_op->output_size)) 974 // LCOV_EXCL_START 975 return CeedError(composite_op->ceed, CEED_ERROR_MAJOR, 976 "Sub-operators must have compatible dimensions; " 977 "composite operator of shape (%td, %td) not compatible with " 978 "sub-operator of shape (%td, %td)", 979 composite_op->input_size, composite_op->output_size, input_size, output_size); 980 // LCOV_EXCL_STOP 981 } 982 983 composite_op->sub_operators[composite_op->num_suboperators] = sub_op; 984 ierr = CeedOperatorReference(sub_op); CeedChk(ierr); 985 composite_op->num_suboperators++; 986 return CEED_ERROR_SUCCESS; 987 } 988 989 /** 990 @brief Check if a CeedOperator is ready to be used. 991 992 @param[in] op CeedOperator to check 993 994 @return An error code: 0 - success, otherwise - failure 995 996 @ref User 997 **/ 998 int CeedOperatorCheckReady(CeedOperator op) { 999 int ierr; 1000 Ceed ceed; 1001 ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); 1002 1003 if (op->is_interface_setup) 1004 return CEED_ERROR_SUCCESS; 1005 1006 CeedQFunction qf = op->qf; 1007 if (op->is_composite) { 1008 if (!op->num_suboperators) 1009 // LCOV_EXCL_START 1010 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No sub_operators set"); 1011 // LCOV_EXCL_STOP 1012 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1013 ierr = CeedOperatorCheckReady(op->sub_operators[i]); CeedChk(ierr); 1014 } 1015 // Sub-operators could be modified after adding to composite operator 1016 // Need to verify no lvec incompatibility from any changes 1017 CeedSize input_size, output_size; 1018 ierr = CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size); 1019 CeedChk(ierr); 1020 } else { 1021 if (op->num_fields == 0) 1022 // LCOV_EXCL_START 1023 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No operator fields set"); 1024 // LCOV_EXCL_STOP 1025 if (op->num_fields < qf->num_input_fields + qf->num_output_fields) 1026 // LCOV_EXCL_START 1027 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set"); 1028 // LCOV_EXCL_STOP 1029 if (!op->has_restriction) 1030 // LCOV_EXCL_START 1031 return CeedError(ceed, CEED_ERROR_INCOMPLETE, 1032 "At least one restriction required"); 1033 // LCOV_EXCL_STOP 1034 if (op->num_qpts == 0) 1035 // LCOV_EXCL_START 1036 return CeedError(ceed, CEED_ERROR_INCOMPLETE, 1037 "At least one non-collocated basis is required " 1038 "or the number of quadrature points must be set"); 1039 // LCOV_EXCL_STOP 1040 } 1041 1042 // Flag as immutable and ready 1043 op->is_interface_setup = true; 1044 if (op->qf && op->qf != CEED_QFUNCTION_NONE) 1045 // LCOV_EXCL_START 1046 op->qf->is_immutable = true; 1047 // LCOV_EXCL_STOP 1048 if (op->dqf && op->dqf != CEED_QFUNCTION_NONE) 1049 // LCOV_EXCL_START 1050 op->dqf->is_immutable = true; 1051 // LCOV_EXCL_STOP 1052 if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE) 1053 // LCOV_EXCL_START 1054 op->dqfT->is_immutable = true; 1055 // LCOV_EXCL_STOP 1056 return CEED_ERROR_SUCCESS; 1057 } 1058 1059 /** 1060 @brief Get vector lengths for the active input and/or output vectors of a CeedOperator. 1061 Note: Lengths of -1 indicate that the CeedOperator does not have an 1062 active input and/or output. 1063 1064 @param[in] op CeedOperator 1065 @param[out] input_size Variable to store active input vector length, or NULL 1066 @param[out] output_size Variable to store active output vector length, or NULL 1067 1068 @return An error code: 0 - success, otherwise - failure 1069 1070 @ref User 1071 **/ 1072 int CeedOperatorGetActiveVectorLengths(CeedOperator op, CeedSize *input_size, 1073 CeedSize *output_size) { 1074 int ierr; 1075 bool is_composite; 1076 1077 if (input_size) *input_size = op->input_size; 1078 if (output_size) *output_size = op->output_size; 1079 1080 ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1081 if (is_composite && (op->input_size == -1 || op->output_size == -1)) { 1082 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1083 CeedSize sub_input_size, sub_output_size; 1084 ierr = CeedOperatorGetActiveVectorLengths(op->sub_operators[i], 1085 &sub_input_size, &sub_output_size); CeedChk(ierr); 1086 if (op->input_size == -1) op->input_size = sub_input_size; 1087 if (op->output_size == -1) op->output_size = sub_output_size; 1088 // Note, a size of -1 means no active vector restriction set, so no incompatibility 1089 if ((sub_input_size != -1 && sub_input_size != op->input_size) || 1090 (sub_output_size != -1 && sub_output_size != op->output_size)) 1091 // LCOV_EXCL_START 1092 return CeedError(op->ceed, CEED_ERROR_MAJOR, 1093 "Sub-operators must have compatible dimensions; " 1094 "composite operator of shape (%td, %td) not compatible with " 1095 "sub-operator of shape (%td, %td)", 1096 op->input_size, op->output_size, input_size, output_size); 1097 // LCOV_EXCL_STOP 1098 } 1099 } 1100 1101 return CEED_ERROR_SUCCESS; 1102 } 1103 1104 /** 1105 @brief Set reuse of CeedQFunction data in CeedOperatorLinearAssemble* functions. 1106 When `reuse_assembly_data = false` (default), the CeedQFunction associated 1107 with this CeedOperator is re-assembled every time a `CeedOperatorLinearAssemble*` 1108 function is called. 1109 When `reuse_assembly_data = true`, the CeedQFunction associated with 1110 this CeedOperator is reused between calls to 1111 `CeedOperatorSetQFunctionAssemblyDataUpdated`. 1112 1113 @param[in] op CeedOperator 1114 @param[in] reuse_assembly_data Boolean flag setting assembly data reuse 1115 1116 @return An error code: 0 - success, otherwise - failure 1117 1118 @ref Advanced 1119 **/ 1120 int CeedOperatorSetQFunctionAssemblyReuse(CeedOperator op, 1121 bool reuse_assembly_data) { 1122 int ierr; 1123 bool is_composite; 1124 1125 ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1126 if (is_composite) { 1127 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1128 ierr = CeedOperatorSetQFunctionAssemblyReuse(op->sub_operators[i], 1129 reuse_assembly_data); CeedChk(ierr); 1130 } 1131 } else { 1132 ierr = CeedQFunctionAssemblyDataSetReuse(op->qf_assembled, reuse_assembly_data); 1133 CeedChk(ierr); 1134 } 1135 1136 return CEED_ERROR_SUCCESS; 1137 } 1138 1139 /** 1140 @brief Mark CeedQFunction data as updated and the CeedQFunction as requiring re-assembly. 1141 1142 @param[in] op CeedOperator 1143 @param[in] needs_data_update Boolean flag setting assembly data reuse 1144 1145 @return An error code: 0 - success, otherwise - failure 1146 1147 @ref Advanced 1148 **/ 1149 int CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(CeedOperator op, 1150 bool needs_data_update) { 1151 int ierr; 1152 bool is_composite; 1153 1154 ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1155 if (is_composite) { 1156 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1157 ierr = CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(op->sub_operators[i], 1158 needs_data_update); CeedChk(ierr); 1159 } 1160 } else { 1161 ierr = CeedQFunctionAssemblyDataSetUpdateNeeded(op->qf_assembled, 1162 needs_data_update); 1163 CeedChk(ierr); 1164 } 1165 1166 return CEED_ERROR_SUCCESS; 1167 } 1168 1169 /** 1170 @brief Set the number of quadrature points associated with a CeedOperator. 1171 This should be used when creating a CeedOperator where every 1172 field has a collocated basis. This function cannot be used for 1173 composite CeedOperators. 1174 1175 @param op CeedOperator 1176 @param num_qpts Number of quadrature points to set 1177 1178 @return An error code: 0 - success, otherwise - failure 1179 1180 @ref Advanced 1181 **/ 1182 int CeedOperatorSetNumQuadraturePoints(CeedOperator op, CeedInt num_qpts) { 1183 if (op->is_composite) 1184 // LCOV_EXCL_START 1185 return CeedError(op->ceed, CEED_ERROR_MINOR, 1186 "Not defined for composite operator"); 1187 // LCOV_EXCL_STOP 1188 if (op->num_qpts) 1189 // LCOV_EXCL_START 1190 return CeedError(op->ceed, CEED_ERROR_MINOR, 1191 "Number of quadrature points already defined"); 1192 // LCOV_EXCL_STOP 1193 if (op->is_immutable) 1194 // LCOV_EXCL_START 1195 return CeedError(op->ceed, CEED_ERROR_MAJOR, 1196 "Operator cannot be changed after set as immutable"); 1197 // LCOV_EXCL_STOP 1198 1199 op->num_qpts = num_qpts; 1200 return CEED_ERROR_SUCCESS; 1201 } 1202 1203 /** 1204 @brief Set name of CeedOperator for CeedOperatorView output 1205 1206 @param op CeedOperator 1207 @param name Name to set, or NULL to remove previously set name 1208 1209 @return An error code: 0 - success, otherwise - failure 1210 1211 @ref User 1212 **/ 1213 int CeedOperatorSetName(CeedOperator op, const char *name) { 1214 int ierr; 1215 char *name_copy; 1216 size_t name_len = name ? strlen(name) : 0; 1217 1218 ierr = CeedFree(&op->name); CeedChk(ierr); 1219 if (name_len > 0) { 1220 ierr = CeedCalloc(name_len + 1, &name_copy); CeedChk(ierr); 1221 memcpy(name_copy, name, name_len); 1222 op->name = name_copy; 1223 } 1224 1225 return CEED_ERROR_SUCCESS; 1226 } 1227 1228 /** 1229 @brief View a CeedOperator 1230 1231 @param[in] op CeedOperator to view 1232 @param[in] stream Stream to write; typically stdout/stderr or a file 1233 1234 @return Error code: 0 - success, otherwise - failure 1235 1236 @ref User 1237 **/ 1238 int CeedOperatorView(CeedOperator op, FILE *stream) { 1239 int ierr; 1240 bool has_name = op->name; 1241 1242 if (op->is_composite) { 1243 fprintf(stream, "Composite CeedOperator%s%s\n", 1244 has_name ? " - " : "", has_name ? op->name : ""); 1245 1246 for (CeedInt i=0; i<op->num_suboperators; i++) { 1247 has_name = op->sub_operators[i]->name; 1248 fprintf(stream, " SubOperator %" CeedInt_FMT "%s%s:\n", i, 1249 has_name ? " - " : "", 1250 has_name ? op->sub_operators[i]->name : ""); 1251 ierr = CeedOperatorSingleView(op->sub_operators[i], 1, stream); 1252 CeedChk(ierr); 1253 } 1254 } else { 1255 fprintf(stream, "CeedOperator%s%s\n", 1256 has_name ? " - " : "", has_name ? op->name : ""); 1257 ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr); 1258 } 1259 return CEED_ERROR_SUCCESS; 1260 } 1261 1262 /** 1263 @brief Get the Ceed associated with a CeedOperator 1264 1265 @param op CeedOperator 1266 @param[out] ceed Variable to store Ceed 1267 1268 @return An error code: 0 - success, otherwise - failure 1269 1270 @ref Advanced 1271 **/ 1272 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) { 1273 *ceed = op->ceed; 1274 return CEED_ERROR_SUCCESS; 1275 } 1276 1277 /** 1278 @brief Get the number of elements associated with a CeedOperator 1279 1280 @param op CeedOperator 1281 @param[out] num_elem Variable to store number of elements 1282 1283 @return An error code: 0 - success, otherwise - failure 1284 1285 @ref Advanced 1286 **/ 1287 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) { 1288 if (op->is_composite) 1289 // LCOV_EXCL_START 1290 return CeedError(op->ceed, CEED_ERROR_MINOR, 1291 "Not defined for composite operator"); 1292 // LCOV_EXCL_STOP 1293 1294 *num_elem = op->num_elem; 1295 return CEED_ERROR_SUCCESS; 1296 } 1297 1298 /** 1299 @brief Get the number of quadrature points associated with a CeedOperator 1300 1301 @param op CeedOperator 1302 @param[out] num_qpts Variable to store vector number of quadrature points 1303 1304 @return An error code: 0 - success, otherwise - failure 1305 1306 @ref Advanced 1307 **/ 1308 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) { 1309 if (op->is_composite) 1310 // LCOV_EXCL_START 1311 return CeedError(op->ceed, CEED_ERROR_MINOR, 1312 "Not defined for composite operator"); 1313 // LCOV_EXCL_STOP 1314 1315 *num_qpts = op->num_qpts; 1316 return CEED_ERROR_SUCCESS; 1317 } 1318 1319 /** 1320 @brief Estimate number of FLOPs required to apply CeedOperator on the active vector 1321 1322 @param op Operator to estimate FLOPs for 1323 @param flops Address of variable to hold FLOPs estimate 1324 1325 @ref Backend 1326 **/ 1327 int CeedOperatorGetFlopsEstimate(CeedOperator op, CeedSize *flops) { 1328 int ierr; 1329 bool is_composite; 1330 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1331 1332 *flops = 0; 1333 ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1334 if (is_composite) { 1335 CeedInt num_suboperators; 1336 ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1337 CeedOperator *sub_operators; 1338 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1339 1340 // FLOPs for each suboperator 1341 for (CeedInt i = 0; i < num_suboperators; i++) { 1342 CeedSize suboperator_flops; 1343 ierr = CeedOperatorGetFlopsEstimate(sub_operators[i], &suboperator_flops); 1344 CeedChk(ierr); 1345 *flops += suboperator_flops; 1346 } 1347 } else { 1348 CeedInt num_input_fields, num_output_fields; 1349 CeedOperatorField *input_fields, *output_fields; 1350 1351 ierr = CeedOperatorGetFields(op, &num_input_fields, &input_fields, 1352 &num_output_fields, &output_fields); CeedChk(ierr); 1353 1354 CeedInt num_elem = 0; 1355 ierr = CeedOperatorGetNumElements(op, &num_elem); CeedChk(ierr); 1356 // Input FLOPs 1357 for (CeedInt i = 0; i < num_input_fields; i++) { 1358 if (input_fields[i]->vec == CEED_VECTOR_ACTIVE) { 1359 CeedSize restr_flops, basis_flops; 1360 1361 ierr = CeedElemRestrictionGetFlopsEstimate(input_fields[i]->elem_restr, 1362 CEED_NOTRANSPOSE, &restr_flops); CeedChk(ierr); 1363 *flops += restr_flops; 1364 ierr = CeedBasisGetFlopsEstimate(input_fields[i]->basis, CEED_NOTRANSPOSE, 1365 op->qf->input_fields[i]->eval_mode, &basis_flops); CeedChk(ierr); 1366 *flops += basis_flops * num_elem; 1367 } 1368 } 1369 // QF FLOPs 1370 CeedInt num_qpts; 1371 CeedSize qf_flops; 1372 ierr = CeedOperatorGetNumQuadraturePoints(op, &num_qpts); CeedChk(ierr); 1373 ierr = CeedQFunctionGetFlopsEstimate(op->qf, &qf_flops); CeedChk(ierr); 1374 *flops += num_elem * num_qpts * qf_flops; 1375 // Output FLOPs 1376 for (CeedInt i = 0; i < num_output_fields; i++) { 1377 if (output_fields[i]->vec == CEED_VECTOR_ACTIVE) { 1378 CeedSize restr_flops, basis_flops; 1379 1380 ierr = CeedElemRestrictionGetFlopsEstimate(output_fields[i]->elem_restr, 1381 CEED_TRANSPOSE, &restr_flops); CeedChk(ierr); 1382 *flops += restr_flops; 1383 ierr = CeedBasisGetFlopsEstimate(output_fields[i]->basis, CEED_TRANSPOSE, 1384 op->qf->output_fields[i]->eval_mode, &basis_flops); CeedChk(ierr); 1385 *flops += basis_flops * num_elem; 1386 } 1387 } 1388 } 1389 1390 return CEED_ERROR_SUCCESS; 1391 } 1392 1393 /** 1394 @brief Get label for a registered QFunctionContext field, or `NULL` if no 1395 field has been registered with this `field_name`. 1396 1397 @param[in] op CeedOperator 1398 @param[in] field_name Name of field to retrieve label 1399 @param[out] field_label Variable to field label 1400 1401 @return An error code: 0 - success, otherwise - failure 1402 1403 @ref User 1404 **/ 1405 int CeedOperatorContextGetFieldLabel(CeedOperator op, 1406 const char *field_name, 1407 CeedContextFieldLabel *field_label) { 1408 int ierr; 1409 1410 bool is_composite; 1411 ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr); 1412 if (is_composite) { 1413 // Check if composite label already created 1414 for (CeedInt i=0; i<op->num_context_labels; i++) { 1415 if (!strcmp(op->context_labels[i]->name, field_name)) { 1416 *field_label = op->context_labels[i]; 1417 return CEED_ERROR_SUCCESS; 1418 } 1419 } 1420 1421 // Create composite label if needed 1422 CeedInt num_sub; 1423 CeedOperator *sub_operators; 1424 CeedContextFieldLabel new_field_label; 1425 1426 ierr = CeedCalloc(1, &new_field_label); CeedChk(ierr); 1427 ierr = CeedOperatorGetNumSub(op, &num_sub); CeedChk(ierr); 1428 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1429 ierr = CeedCalloc(num_sub, &new_field_label->sub_labels); CeedChk(ierr); 1430 new_field_label->num_sub_labels = num_sub; 1431 1432 bool label_found = false; 1433 for (CeedInt i=0; i<num_sub; i++) { 1434 if (sub_operators[i]->qf->ctx) { 1435 CeedContextFieldLabel new_field_label_i; 1436 ierr = CeedQFunctionContextGetFieldLabel(sub_operators[i]->qf->ctx, field_name, 1437 &new_field_label_i); CeedChk(ierr); 1438 if (new_field_label_i) { 1439 label_found = true; 1440 new_field_label->sub_labels[i] = new_field_label_i; 1441 new_field_label->name = new_field_label_i->name; 1442 new_field_label->description = new_field_label_i->description; 1443 if (new_field_label->type && 1444 new_field_label->type != new_field_label_i->type) { 1445 // LCOV_EXCL_START 1446 ierr = CeedFree(&new_field_label); CeedChk(ierr); 1447 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 1448 "Incompatible field types on sub-operator contexts. " 1449 "%s != %s", 1450 CeedContextFieldTypes[new_field_label->type], 1451 CeedContextFieldTypes[new_field_label_i->type]); 1452 // LCOV_EXCL_STOP 1453 } else { 1454 new_field_label->type = new_field_label_i->type; 1455 } 1456 if (new_field_label->num_values != 0 && 1457 new_field_label->num_values != new_field_label_i->num_values) { 1458 // LCOV_EXCL_START 1459 ierr = CeedFree(&new_field_label); CeedChk(ierr); 1460 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, 1461 "Incompatible field number of values on sub-operator" 1462 " contexts. %ld != %ld", 1463 new_field_label->num_values, new_field_label_i->num_values); 1464 // LCOV_EXCL_STOP 1465 } else { 1466 new_field_label->num_values = new_field_label_i->num_values; 1467 } 1468 } 1469 } 1470 } 1471 if (!label_found) { 1472 // LCOV_EXCL_START 1473 ierr = CeedFree(&new_field_label->sub_labels); CeedChk(ierr); 1474 ierr = CeedFree(&new_field_label); CeedChk(ierr); 1475 *field_label = NULL; 1476 // LCOV_EXCL_STOP 1477 } else { 1478 // Move new composite label to operator 1479 if (op->num_context_labels == 0) { 1480 ierr = CeedCalloc(1, &op->context_labels); CeedChk(ierr); 1481 op->max_context_labels = 1; 1482 } else if (op->num_context_labels == op->max_context_labels) { 1483 ierr = CeedRealloc(2*op->num_context_labels, &op->context_labels); 1484 CeedChk(ierr); 1485 op->max_context_labels *= 2; 1486 } 1487 op->context_labels[op->num_context_labels] = new_field_label; 1488 *field_label = new_field_label; 1489 op->num_context_labels++; 1490 } 1491 1492 return CEED_ERROR_SUCCESS; 1493 } else { 1494 return CeedQFunctionContextGetFieldLabel(op->qf->ctx, field_name, field_label); 1495 } 1496 } 1497 1498 /** 1499 @brief Set QFunctionContext field holding a double precision value. 1500 For composite operators, the value is set in all 1501 sub-operator QFunctionContexts that have a matching `field_name`. 1502 1503 @param op CeedOperator 1504 @param field_label Label of field to register 1505 @param values Values to set 1506 1507 @return An error code: 0 - success, otherwise - failure 1508 1509 @ref User 1510 **/ 1511 int CeedOperatorContextSetDouble(CeedOperator op, 1512 CeedContextFieldLabel field_label, 1513 double *values) { 1514 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, 1515 values); 1516 } 1517 1518 /** 1519 @brief Set QFunctionContext field holding an int32 value. 1520 For composite operators, the value is set in all 1521 sub-operator QFunctionContexts that have a matching `field_name`. 1522 1523 @param op CeedOperator 1524 @param field_label Label of field to set 1525 @param values Values to set 1526 1527 @return An error code: 0 - success, otherwise - failure 1528 1529 @ref User 1530 **/ 1531 int CeedOperatorContextSetInt32(CeedOperator op, 1532 CeedContextFieldLabel field_label, 1533 int *values) { 1534 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_INT32, 1535 values); 1536 } 1537 1538 /** 1539 @brief Apply CeedOperator to a vector 1540 1541 This computes the action of the operator on the specified (active) input, 1542 yielding its (active) output. All inputs and outputs must be specified using 1543 CeedOperatorSetField(). 1544 1545 Note: Calling this function asserts that setup is complete 1546 and sets the CeedOperator as immutable. 1547 1548 @param op CeedOperator to apply 1549 @param[in] in CeedVector containing input state or @ref CEED_VECTOR_NONE if 1550 there are no active inputs 1551 @param[out] out CeedVector to store result of applying operator (must be 1552 distinct from @a in) or @ref CEED_VECTOR_NONE if there are no 1553 active outputs 1554 @param request Address of CeedRequest for non-blocking completion, else 1555 @ref CEED_REQUEST_IMMEDIATE 1556 1557 @return An error code: 0 - success, otherwise - failure 1558 1559 @ref User 1560 **/ 1561 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, 1562 CeedRequest *request) { 1563 int ierr; 1564 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1565 1566 if (op->num_elem) { 1567 // Standard Operator 1568 if (op->Apply) { 1569 ierr = op->Apply(op, in, out, request); CeedChk(ierr); 1570 } else { 1571 // Zero all output vectors 1572 CeedQFunction qf = op->qf; 1573 for (CeedInt i=0; i<qf->num_output_fields; i++) { 1574 CeedVector vec = op->output_fields[i]->vec; 1575 if (vec == CEED_VECTOR_ACTIVE) 1576 vec = out; 1577 if (vec != CEED_VECTOR_NONE) { 1578 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 1579 } 1580 } 1581 // Apply 1582 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 1583 } 1584 } else if (op->is_composite) { 1585 // Composite Operator 1586 if (op->ApplyComposite) { 1587 ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr); 1588 } else { 1589 CeedInt num_suboperators; 1590 ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1591 CeedOperator *sub_operators; 1592 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1593 1594 // Zero all output vectors 1595 if (out != CEED_VECTOR_NONE) { 1596 ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr); 1597 } 1598 for (CeedInt i=0; i<num_suboperators; i++) { 1599 for (CeedInt j=0; j<sub_operators[i]->qf->num_output_fields; j++) { 1600 CeedVector vec = sub_operators[i]->output_fields[j]->vec; 1601 if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) { 1602 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 1603 } 1604 } 1605 } 1606 // Apply 1607 for (CeedInt i=0; i<op->num_suboperators; i++) { 1608 ierr = CeedOperatorApplyAdd(op->sub_operators[i], in, out, request); 1609 CeedChk(ierr); 1610 } 1611 } 1612 } 1613 return CEED_ERROR_SUCCESS; 1614 } 1615 1616 /** 1617 @brief Apply CeedOperator to a vector and add result to output vector 1618 1619 This computes the action of the operator on the specified (active) input, 1620 yielding its (active) output. All inputs and outputs must be specified using 1621 CeedOperatorSetField(). 1622 1623 @param op CeedOperator to apply 1624 @param[in] in CeedVector containing input state or NULL if there are no 1625 active inputs 1626 @param[out] out CeedVector to sum in result of applying operator (must be 1627 distinct from @a in) or NULL if there are no active outputs 1628 @param request Address of CeedRequest for non-blocking completion, else 1629 @ref CEED_REQUEST_IMMEDIATE 1630 1631 @return An error code: 0 - success, otherwise - failure 1632 1633 @ref User 1634 **/ 1635 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, 1636 CeedRequest *request) { 1637 int ierr; 1638 ierr = CeedOperatorCheckReady(op); CeedChk(ierr); 1639 1640 if (op->num_elem) { 1641 // Standard Operator 1642 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 1643 } else if (op->is_composite) { 1644 // Composite Operator 1645 if (op->ApplyAddComposite) { 1646 ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr); 1647 } else { 1648 CeedInt num_suboperators; 1649 ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr); 1650 CeedOperator *sub_operators; 1651 ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr); 1652 1653 for (CeedInt i=0; i<num_suboperators; i++) { 1654 ierr = CeedOperatorApplyAdd(sub_operators[i], in, out, request); 1655 CeedChk(ierr); 1656 } 1657 } 1658 } 1659 return CEED_ERROR_SUCCESS; 1660 } 1661 1662 /** 1663 @brief Destroy a CeedOperator 1664 1665 @param op CeedOperator to destroy 1666 1667 @return An error code: 0 - success, otherwise - failure 1668 1669 @ref User 1670 **/ 1671 int CeedOperatorDestroy(CeedOperator *op) { 1672 int ierr; 1673 1674 if (!*op || --(*op)->ref_count > 0) return CEED_ERROR_SUCCESS; 1675 if ((*op)->Destroy) { 1676 ierr = (*op)->Destroy(*op); CeedChk(ierr); 1677 } 1678 ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr); 1679 // Free fields 1680 for (CeedInt i=0; i<(*op)->num_fields; i++) 1681 if ((*op)->input_fields[i]) { 1682 if ((*op)->input_fields[i]->elem_restr != CEED_ELEMRESTRICTION_NONE) { 1683 ierr = CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_restr); 1684 CeedChk(ierr); 1685 } 1686 if ((*op)->input_fields[i]->basis != CEED_BASIS_COLLOCATED) { 1687 ierr = CeedBasisDestroy(&(*op)->input_fields[i]->basis); CeedChk(ierr); 1688 } 1689 if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE && 1690 (*op)->input_fields[i]->vec != CEED_VECTOR_NONE ) { 1691 ierr = CeedVectorDestroy(&(*op)->input_fields[i]->vec); CeedChk(ierr); 1692 } 1693 ierr = CeedFree(&(*op)->input_fields[i]->field_name); CeedChk(ierr); 1694 ierr = CeedFree(&(*op)->input_fields[i]); CeedChk(ierr); 1695 } 1696 for (CeedInt i=0; i<(*op)->num_fields; i++) 1697 if ((*op)->output_fields[i]) { 1698 ierr = CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_restr); 1699 CeedChk(ierr); 1700 if ((*op)->output_fields[i]->basis != CEED_BASIS_COLLOCATED) { 1701 ierr = CeedBasisDestroy(&(*op)->output_fields[i]->basis); CeedChk(ierr); 1702 } 1703 if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE && 1704 (*op)->output_fields[i]->vec != CEED_VECTOR_NONE ) { 1705 ierr = CeedVectorDestroy(&(*op)->output_fields[i]->vec); CeedChk(ierr); 1706 } 1707 ierr = CeedFree(&(*op)->output_fields[i]->field_name); CeedChk(ierr); 1708 ierr = CeedFree(&(*op)->output_fields[i]); CeedChk(ierr); 1709 } 1710 // Destroy sub_operators 1711 for (CeedInt i=0; i<(*op)->num_suboperators; i++) 1712 if ((*op)->sub_operators[i]) { 1713 ierr = CeedOperatorDestroy(&(*op)->sub_operators[i]); CeedChk(ierr); 1714 } 1715 ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr); 1716 ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr); 1717 ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr); 1718 // Destroy any composite labels 1719 for (CeedInt i=0; i<(*op)->num_context_labels; i++) { 1720 ierr = CeedFree(&(*op)->context_labels[i]->sub_labels); CeedChk(ierr); 1721 ierr = CeedFree(&(*op)->context_labels[i]); CeedChk(ierr); 1722 } 1723 ierr = CeedFree(&(*op)->context_labels); CeedChk(ierr); 1724 1725 // Destroy fallback 1726 ierr = CeedOperatorDestroy(&(*op)->op_fallback); CeedChk(ierr); 1727 1728 // Destroy assembly data 1729 ierr = CeedQFunctionAssemblyDataDestroy(&(*op)->qf_assembled); CeedChk(ierr); 1730 ierr = CeedOperatorAssemblyDataDestroy(&(*op)->op_assembled); CeedChk(ierr); 1731 1732 ierr = CeedFree(&(*op)->input_fields); CeedChk(ierr); 1733 ierr = CeedFree(&(*op)->output_fields); CeedChk(ierr); 1734 ierr = CeedFree(&(*op)->sub_operators); CeedChk(ierr); 1735 ierr = CeedFree(&(*op)->name); CeedChk(ierr); 1736 ierr = CeedFree(op); CeedChk(ierr); 1737 return CEED_ERROR_SUCCESS; 1738 } 1739 1740 /// @} 1741