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