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