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