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