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