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 the name of a CeedOperatorField 875 876 @param[in] op_field CeedOperatorField 877 @param[out] field_name Variable to store the field name 878 879 @return An error code: 0 - success, otherwise - failure 880 881 @ref Advanced 882 **/ 883 int CeedOperatorFieldGetName(CeedOperatorField op_field, char **field_name) { 884 *field_name = (char *)op_field->field_name; 885 return CEED_ERROR_SUCCESS; 886 } 887 888 /** 889 @brief Get the CeedElemRestriction of a CeedOperatorField 890 891 @param[in] op_field CeedOperatorField 892 @param[out] rstr Variable to store CeedElemRestriction 893 894 @return An error code: 0 - success, otherwise - failure 895 896 @ref Advanced 897 **/ 898 int CeedOperatorFieldGetElemRestriction(CeedOperatorField op_field, CeedElemRestriction *rstr) { 899 *rstr = op_field->elem_rstr; 900 return CEED_ERROR_SUCCESS; 901 } 902 903 /** 904 @brief Get the CeedBasis of a CeedOperatorField 905 906 @param[in] op_field CeedOperatorField 907 @param[out] basis Variable to store CeedBasis 908 909 @return An error code: 0 - success, otherwise - failure 910 911 @ref Advanced 912 **/ 913 int CeedOperatorFieldGetBasis(CeedOperatorField op_field, CeedBasis *basis) { 914 *basis = op_field->basis; 915 return CEED_ERROR_SUCCESS; 916 } 917 918 /** 919 @brief Get the CeedVector of a CeedOperatorField 920 921 @param[in] op_field CeedOperatorField 922 @param[out] vec Variable to store CeedVector 923 924 @return An error code: 0 - success, otherwise - failure 925 926 @ref Advanced 927 **/ 928 int CeedOperatorFieldGetVector(CeedOperatorField op_field, CeedVector *vec) { 929 *vec = op_field->vec; 930 return CEED_ERROR_SUCCESS; 931 } 932 933 /** 934 @brief Add a sub-operator to a composite CeedOperator 935 936 @param[in,out] composite_op Composite CeedOperator 937 @param[in] sub_op Sub-operator CeedOperator 938 939 @return An error code: 0 - success, otherwise - failure 940 941 @ref User 942 */ 943 int CeedCompositeOperatorAddSub(CeedOperator composite_op, CeedOperator sub_op) { 944 if (!composite_op->is_composite) { 945 // LCOV_EXCL_START 946 return CeedError(composite_op->ceed, CEED_ERROR_MINOR, "CeedOperator is not a composite operator"); 947 // LCOV_EXCL_STOP 948 } 949 950 if (composite_op->num_suboperators == CEED_COMPOSITE_MAX) { 951 // LCOV_EXCL_START 952 return CeedError(composite_op->ceed, CEED_ERROR_UNSUPPORTED, "Cannot add additional sub-operators"); 953 // LCOV_EXCL_STOP 954 } 955 if (composite_op->is_immutable) { 956 // LCOV_EXCL_START 957 return CeedError(composite_op->ceed, CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable"); 958 // LCOV_EXCL_STOP 959 } 960 961 { 962 CeedSize input_size, output_size; 963 CeedCall(CeedOperatorGetActiveVectorLengths(sub_op, &input_size, &output_size)); 964 if (composite_op->input_size == -1) composite_op->input_size = input_size; 965 if (composite_op->output_size == -1) composite_op->output_size = output_size; 966 // Note, a size of -1 means no active vector restriction set, so no incompatibility 967 if ((input_size != -1 && input_size != composite_op->input_size) || (output_size != -1 && output_size != composite_op->output_size)) { 968 // LCOV_EXCL_START 969 return CeedError(composite_op->ceed, CEED_ERROR_MAJOR, 970 "Sub-operators must have compatible dimensions; composite operator of shape (%td, %td) not compatible with sub-operator of " 971 "shape (%td, %td)", 972 composite_op->input_size, composite_op->output_size, input_size, output_size); 973 // LCOV_EXCL_STOP 974 } 975 } 976 977 composite_op->sub_operators[composite_op->num_suboperators] = sub_op; 978 CeedCall(CeedOperatorReference(sub_op)); 979 composite_op->num_suboperators++; 980 return CEED_ERROR_SUCCESS; 981 } 982 983 /** 984 @brief Get the number of sub_operators associated with a CeedOperator 985 986 @param[in] op CeedOperator 987 @param[out] num_suboperators Variable to store number of sub_operators 988 989 @return An error code: 0 - success, otherwise - failure 990 991 @ref Backend 992 **/ 993 994 int CeedCompositeOperatorGetNumSub(CeedOperator op, CeedInt *num_suboperators) { 995 if (!op->is_composite) { 996 // LCOV_EXCL_START 997 return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator"); 998 // LCOV_EXCL_STOP 999 } 1000 *num_suboperators = op->num_suboperators; 1001 return CEED_ERROR_SUCCESS; 1002 } 1003 1004 /** 1005 @brief Get the list of sub_operators associated with a CeedOperator 1006 1007 @param op CeedOperator 1008 @param[out] sub_operators Variable to store list of sub_operators 1009 1010 @return An error code: 0 - success, otherwise - failure 1011 1012 @ref Backend 1013 **/ 1014 1015 int CeedCompositeOperatorGetSubList(CeedOperator op, CeedOperator **sub_operators) { 1016 if (!op->is_composite) { 1017 // LCOV_EXCL_START 1018 return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator"); 1019 // LCOV_EXCL_STOP 1020 } 1021 *sub_operators = op->sub_operators; 1022 return CEED_ERROR_SUCCESS; 1023 } 1024 1025 /** 1026 @brief Check if a CeedOperator is ready to be used. 1027 1028 @param[in] op CeedOperator to check 1029 1030 @return An error code: 0 - success, otherwise - failure 1031 1032 @ref User 1033 **/ 1034 int CeedOperatorCheckReady(CeedOperator op) { 1035 Ceed ceed; 1036 CeedCall(CeedOperatorGetCeed(op, &ceed)); 1037 1038 if (op->is_interface_setup) return CEED_ERROR_SUCCESS; 1039 1040 CeedQFunction qf = op->qf; 1041 if (op->is_composite) { 1042 if (!op->num_suboperators) { 1043 // Empty operator setup 1044 op->input_size = 0; 1045 op->output_size = 0; 1046 } else { 1047 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1048 CeedCall(CeedOperatorCheckReady(op->sub_operators[i])); 1049 } 1050 // Sub-operators could be modified after adding to composite operator 1051 // Need to verify no lvec incompatibility from any changes 1052 CeedSize input_size, output_size; 1053 CeedCall(CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size)); 1054 } 1055 } else { 1056 if (op->num_fields == 0) { 1057 // LCOV_EXCL_START 1058 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No operator fields set"); 1059 // LCOV_EXCL_STOP 1060 } 1061 if (op->num_fields < qf->num_input_fields + qf->num_output_fields) { 1062 // LCOV_EXCL_START 1063 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set"); 1064 // LCOV_EXCL_STOP 1065 } 1066 if (!op->has_restriction) { 1067 // LCOV_EXCL_START 1068 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "At least one restriction required"); 1069 // LCOV_EXCL_STOP 1070 } 1071 if (op->num_qpts == 0) { 1072 // LCOV_EXCL_START 1073 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "At least one non-collocated basis is required or the number of quadrature points must be set"); 1074 // LCOV_EXCL_STOP 1075 } 1076 } 1077 1078 // Flag as immutable and ready 1079 op->is_interface_setup = true; 1080 if (op->qf && op->qf != CEED_QFUNCTION_NONE) op->qf->is_immutable = true; 1081 if (op->dqf && op->dqf != CEED_QFUNCTION_NONE) op->dqf->is_immutable = true; 1082 if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE) op->dqfT->is_immutable = true; 1083 return CEED_ERROR_SUCCESS; 1084 } 1085 1086 /** 1087 @brief Get vector lengths for the active input and/or output vectors of a CeedOperator. 1088 Note: Lengths of -1 indicate that the CeedOperator does not have an active input and/or output. 1089 1090 @param[in] op CeedOperator 1091 @param[out] input_size Variable to store active input vector length, or NULL 1092 @param[out] output_size Variable to store active output vector length, or NULL 1093 1094 @return An error code: 0 - success, otherwise - failure 1095 1096 @ref User 1097 **/ 1098 int CeedOperatorGetActiveVectorLengths(CeedOperator op, CeedSize *input_size, CeedSize *output_size) { 1099 bool is_composite; 1100 1101 if (input_size) *input_size = op->input_size; 1102 if (output_size) *output_size = op->output_size; 1103 1104 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1105 if (is_composite && (op->input_size == -1 || op->output_size == -1)) { 1106 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1107 CeedSize sub_input_size, sub_output_size; 1108 CeedCall(CeedOperatorGetActiveVectorLengths(op->sub_operators[i], &sub_input_size, &sub_output_size)); 1109 if (op->input_size == -1) op->input_size = sub_input_size; 1110 if (op->output_size == -1) op->output_size = sub_output_size; 1111 // Note, a size of -1 means no active vector restriction set, so no incompatibility 1112 if ((sub_input_size != -1 && sub_input_size != op->input_size) || (sub_output_size != -1 && sub_output_size != op->output_size)) { 1113 // LCOV_EXCL_START 1114 return CeedError(op->ceed, CEED_ERROR_MAJOR, 1115 "Sub-operators must have compatible dimensions; composite operator of shape (%td, %td) not compatible with sub-operator of " 1116 "shape (%td, %td)", 1117 op->input_size, op->output_size, input_size, output_size); 1118 // LCOV_EXCL_STOP 1119 } 1120 } 1121 } 1122 1123 return CEED_ERROR_SUCCESS; 1124 } 1125 1126 /** 1127 @brief Set reuse of CeedQFunction data in CeedOperatorLinearAssemble* functions. 1128 When `reuse_assembly_data = false` (default), the CeedQFunction associated with this CeedOperator is re-assembled every time a 1129 `CeedOperatorLinearAssemble*` function is called. When `reuse_assembly_data = true`, the CeedQFunction associated with this CeedOperator is reused 1130 between calls to `CeedOperatorSetQFunctionAssemblyDataUpdated`. 1131 1132 @param[in] op CeedOperator 1133 @param[in] reuse_assembly_data Boolean flag setting assembly data reuse 1134 1135 @return An error code: 0 - success, otherwise - failure 1136 1137 @ref Advanced 1138 **/ 1139 int CeedOperatorSetQFunctionAssemblyReuse(CeedOperator op, bool reuse_assembly_data) { 1140 bool is_composite; 1141 1142 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1143 if (is_composite) { 1144 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1145 CeedCall(CeedOperatorSetQFunctionAssemblyReuse(op->sub_operators[i], reuse_assembly_data)); 1146 } 1147 } else { 1148 CeedCall(CeedQFunctionAssemblyDataSetReuse(op->qf_assembled, reuse_assembly_data)); 1149 } 1150 1151 return CEED_ERROR_SUCCESS; 1152 } 1153 1154 /** 1155 @brief Mark CeedQFunction data as updated and the CeedQFunction as requiring re-assembly. 1156 1157 @param[in] op CeedOperator 1158 @param[in] needs_data_update Boolean flag setting assembly data reuse 1159 1160 @return An error code: 0 - success, otherwise - failure 1161 1162 @ref Advanced 1163 **/ 1164 int CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(CeedOperator op, bool needs_data_update) { 1165 bool is_composite; 1166 1167 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1168 if (is_composite) { 1169 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1170 CeedCall(CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(op->sub_operators[i], needs_data_update)); 1171 } 1172 } else { 1173 CeedCall(CeedQFunctionAssemblyDataSetUpdateNeeded(op->qf_assembled, needs_data_update)); 1174 } 1175 1176 return CEED_ERROR_SUCCESS; 1177 } 1178 1179 /** 1180 @brief Set the number of quadrature points associated with a CeedOperator. 1181 This should be used when creating a CeedOperator where every field has a collocated basis. 1182 This function cannot be used for composite CeedOperators. 1183 1184 @param[in,out] op CeedOperator 1185 @param[in] num_qpts Number of quadrature points to set 1186 1187 @return An error code: 0 - success, otherwise - failure 1188 1189 @ref Advanced 1190 **/ 1191 int CeedOperatorSetNumQuadraturePoints(CeedOperator op, CeedInt num_qpts) { 1192 if (op->is_composite) { 1193 // LCOV_EXCL_START 1194 return CeedError(op->ceed, CEED_ERROR_MINOR, "Not defined for composite operator"); 1195 // LCOV_EXCL_STOP 1196 } 1197 if (op->num_qpts) { 1198 // LCOV_EXCL_START 1199 return CeedError(op->ceed, CEED_ERROR_MINOR, "Number of quadrature points already defined"); 1200 // LCOV_EXCL_STOP 1201 } 1202 if (op->is_immutable) { 1203 // LCOV_EXCL_START 1204 return CeedError(op->ceed, CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable"); 1205 // LCOV_EXCL_STOP 1206 } 1207 op->num_qpts = num_qpts; 1208 return CEED_ERROR_SUCCESS; 1209 } 1210 1211 /** 1212 @brief Set name of CeedOperator for CeedOperatorView output 1213 1214 @param[in,out] op CeedOperator 1215 @param[in] name Name to set, or NULL to remove previously set name 1216 1217 @return An error code: 0 - success, otherwise - failure 1218 1219 @ref User 1220 **/ 1221 int CeedOperatorSetName(CeedOperator op, const char *name) { 1222 char *name_copy; 1223 size_t name_len = name ? strlen(name) : 0; 1224 1225 CeedCall(CeedFree(&op->name)); 1226 if (name_len > 0) { 1227 CeedCall(CeedCalloc(name_len + 1, &name_copy)); 1228 memcpy(name_copy, name, name_len); 1229 op->name = name_copy; 1230 } 1231 1232 return CEED_ERROR_SUCCESS; 1233 } 1234 1235 /** 1236 @brief View a CeedOperator 1237 1238 @param[in] op CeedOperator to view 1239 @param[in] stream Stream to write; typically stdout/stderr or a file 1240 1241 @return Error code: 0 - success, otherwise - failure 1242 1243 @ref User 1244 **/ 1245 int CeedOperatorView(CeedOperator op, FILE *stream) { 1246 bool has_name = op->name; 1247 1248 if (op->is_composite) { 1249 fprintf(stream, "Composite CeedOperator%s%s\n", has_name ? " - " : "", has_name ? op->name : ""); 1250 1251 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1252 has_name = op->sub_operators[i]->name; 1253 fprintf(stream, " SubOperator %" CeedInt_FMT "%s%s:\n", i, has_name ? " - " : "", has_name ? op->sub_operators[i]->name : ""); 1254 CeedCall(CeedOperatorSingleView(op->sub_operators[i], 1, stream)); 1255 } 1256 } else { 1257 fprintf(stream, "CeedOperator%s%s\n", has_name ? " - " : "", has_name ? op->name : ""); 1258 CeedCall(CeedOperatorSingleView(op, 0, stream)); 1259 } 1260 return CEED_ERROR_SUCCESS; 1261 } 1262 1263 /** 1264 @brief Get the Ceed associated with a CeedOperator 1265 1266 @param[in] op CeedOperator 1267 @param[out] ceed Variable to store Ceed 1268 1269 @return An error code: 0 - success, otherwise - failure 1270 1271 @ref Advanced 1272 **/ 1273 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) { 1274 *ceed = op->ceed; 1275 return CEED_ERROR_SUCCESS; 1276 } 1277 1278 /** 1279 @brief Get the number of elements associated with a CeedOperator 1280 1281 @param[in] op CeedOperator 1282 @param[out] num_elem Variable to store number of elements 1283 1284 @return An error code: 0 - success, otherwise - failure 1285 1286 @ref Advanced 1287 **/ 1288 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) { 1289 if (op->is_composite) { 1290 // LCOV_EXCL_START 1291 return CeedError(op->ceed, CEED_ERROR_MINOR, "Not defined for composite operator"); 1292 // LCOV_EXCL_STOP 1293 } 1294 *num_elem = op->num_elem; 1295 return CEED_ERROR_SUCCESS; 1296 } 1297 1298 /** 1299 @brief Get the number of quadrature points associated with a CeedOperator 1300 1301 @param[in] op CeedOperator 1302 @param[out] num_qpts Variable to store vector number of quadrature points 1303 1304 @return An error code: 0 - success, otherwise - failure 1305 1306 @ref Advanced 1307 **/ 1308 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) { 1309 if (op->is_composite) { 1310 // LCOV_EXCL_START 1311 return CeedError(op->ceed, CEED_ERROR_MINOR, "Not defined for composite operator"); 1312 // LCOV_EXCL_STOP 1313 } 1314 *num_qpts = op->num_qpts; 1315 return CEED_ERROR_SUCCESS; 1316 } 1317 1318 /** 1319 @brief Estimate number of FLOPs required to apply CeedOperator on the active vector 1320 1321 @param[in] op CeedOperator to estimate FLOPs for 1322 @param[out] flops Address of variable to hold FLOPs estimate 1323 1324 @ref Backend 1325 **/ 1326 int CeedOperatorGetFlopsEstimate(CeedOperator op, CeedSize *flops) { 1327 bool is_composite; 1328 CeedCall(CeedOperatorCheckReady(op)); 1329 1330 *flops = 0; 1331 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1332 if (is_composite) { 1333 CeedInt num_suboperators; 1334 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 1335 CeedOperator *sub_operators; 1336 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1337 1338 // FLOPs for each suboperator 1339 for (CeedInt i = 0; i < num_suboperators; i++) { 1340 CeedSize suboperator_flops; 1341 CeedCall(CeedOperatorGetFlopsEstimate(sub_operators[i], &suboperator_flops)); 1342 *flops += suboperator_flops; 1343 } 1344 } else { 1345 CeedInt num_input_fields, num_output_fields; 1346 CeedOperatorField *input_fields, *output_fields; 1347 1348 CeedCall(CeedOperatorGetFields(op, &num_input_fields, &input_fields, &num_output_fields, &output_fields)); 1349 1350 CeedInt num_elem = 0; 1351 CeedCall(CeedOperatorGetNumElements(op, &num_elem)); 1352 // Input FLOPs 1353 for (CeedInt i = 0; i < num_input_fields; i++) { 1354 if (input_fields[i]->vec == CEED_VECTOR_ACTIVE) { 1355 CeedSize restr_flops, basis_flops; 1356 1357 CeedCall(CeedElemRestrictionGetFlopsEstimate(input_fields[i]->elem_rstr, CEED_NOTRANSPOSE, &restr_flops)); 1358 *flops += restr_flops; 1359 CeedCall(CeedBasisGetFlopsEstimate(input_fields[i]->basis, CEED_NOTRANSPOSE, op->qf->input_fields[i]->eval_mode, &basis_flops)); 1360 *flops += basis_flops * num_elem; 1361 } 1362 } 1363 // QF FLOPs 1364 CeedInt num_qpts; 1365 CeedSize qf_flops; 1366 CeedCall(CeedOperatorGetNumQuadraturePoints(op, &num_qpts)); 1367 CeedCall(CeedQFunctionGetFlopsEstimate(op->qf, &qf_flops)); 1368 *flops += num_elem * num_qpts * qf_flops; 1369 // Output FLOPs 1370 for (CeedInt i = 0; i < num_output_fields; i++) { 1371 if (output_fields[i]->vec == CEED_VECTOR_ACTIVE) { 1372 CeedSize restr_flops, basis_flops; 1373 1374 CeedCall(CeedElemRestrictionGetFlopsEstimate(output_fields[i]->elem_rstr, CEED_TRANSPOSE, &restr_flops)); 1375 *flops += restr_flops; 1376 CeedCall(CeedBasisGetFlopsEstimate(output_fields[i]->basis, CEED_TRANSPOSE, op->qf->output_fields[i]->eval_mode, &basis_flops)); 1377 *flops += basis_flops * num_elem; 1378 } 1379 } 1380 } 1381 1382 return CEED_ERROR_SUCCESS; 1383 } 1384 1385 /** 1386 @brief Get label for a registered QFunctionContext field, or `NULL` if no field has been registered with this `field_name`. 1387 1388 @param[in] op CeedOperator 1389 @param[in] field_name Name of field to retrieve label 1390 @param[out] field_label Variable to field label 1391 1392 @return An error code: 0 - success, otherwise - failure 1393 1394 @ref User 1395 **/ 1396 int CeedOperatorContextGetFieldLabel(CeedOperator op, const char *field_name, CeedContextFieldLabel *field_label) { 1397 bool is_composite; 1398 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1399 1400 if (is_composite) { 1401 // Check if composite label already created 1402 for (CeedInt i = 0; i < op->num_context_labels; i++) { 1403 if (!strcmp(op->context_labels[i]->name, field_name)) { 1404 *field_label = op->context_labels[i]; 1405 return CEED_ERROR_SUCCESS; 1406 } 1407 } 1408 1409 // Create composite label if needed 1410 CeedInt num_sub; 1411 CeedOperator *sub_operators; 1412 CeedContextFieldLabel new_field_label; 1413 1414 CeedCall(CeedCalloc(1, &new_field_label)); 1415 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_sub)); 1416 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1417 CeedCall(CeedCalloc(num_sub, &new_field_label->sub_labels)); 1418 new_field_label->num_sub_labels = num_sub; 1419 1420 bool label_found = false; 1421 for (CeedInt i = 0; i < num_sub; i++) { 1422 if (sub_operators[i]->qf->ctx) { 1423 CeedContextFieldLabel new_field_label_i; 1424 CeedCall(CeedQFunctionContextGetFieldLabel(sub_operators[i]->qf->ctx, field_name, &new_field_label_i)); 1425 if (new_field_label_i) { 1426 label_found = true; 1427 new_field_label->sub_labels[i] = new_field_label_i; 1428 new_field_label->name = new_field_label_i->name; 1429 new_field_label->description = new_field_label_i->description; 1430 if (new_field_label->type && new_field_label->type != new_field_label_i->type) { 1431 // LCOV_EXCL_START 1432 CeedCall(CeedFree(&new_field_label)); 1433 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, "Incompatible field types on sub-operator contexts. %s != %s", 1434 CeedContextFieldTypes[new_field_label->type], CeedContextFieldTypes[new_field_label_i->type]); 1435 // LCOV_EXCL_STOP 1436 } else { 1437 new_field_label->type = new_field_label_i->type; 1438 } 1439 if (new_field_label->num_values != 0 && new_field_label->num_values != new_field_label_i->num_values) { 1440 // LCOV_EXCL_START 1441 CeedCall(CeedFree(&new_field_label)); 1442 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, "Incompatible field number of values on sub-operator contexts. %ld != %ld", 1443 new_field_label->num_values, new_field_label_i->num_values); 1444 // LCOV_EXCL_STOP 1445 } else { 1446 new_field_label->num_values = new_field_label_i->num_values; 1447 } 1448 } 1449 } 1450 } 1451 if (!label_found) { 1452 // LCOV_EXCL_START 1453 CeedCall(CeedFree(&new_field_label->sub_labels)); 1454 CeedCall(CeedFree(&new_field_label)); 1455 *field_label = NULL; 1456 // LCOV_EXCL_STOP 1457 } else { 1458 // Move new composite label to operator 1459 if (op->num_context_labels == 0) { 1460 CeedCall(CeedCalloc(1, &op->context_labels)); 1461 op->max_context_labels = 1; 1462 } else if (op->num_context_labels == op->max_context_labels) { 1463 CeedCall(CeedRealloc(2 * op->num_context_labels, &op->context_labels)); 1464 op->max_context_labels *= 2; 1465 } 1466 op->context_labels[op->num_context_labels] = new_field_label; 1467 *field_label = new_field_label; 1468 op->num_context_labels++; 1469 } 1470 1471 return CEED_ERROR_SUCCESS; 1472 } else { 1473 return CeedQFunctionContextGetFieldLabel(op->qf->ctx, field_name, field_label); 1474 } 1475 } 1476 1477 /** 1478 @brief Set QFunctionContext field holding double precision values. 1479 For composite operators, the values are set in all sub-operator QFunctionContexts that have a matching `field_name`. 1480 1481 @param[in,out] op CeedOperator 1482 @param[in] field_label Label of field to set 1483 @param[in] values Values to set 1484 1485 @return An error code: 0 - success, otherwise - failure 1486 1487 @ref User 1488 **/ 1489 int CeedOperatorContextSetDouble(CeedOperator op, CeedContextFieldLabel field_label, double *values) { 1490 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, values); 1491 } 1492 1493 /** 1494 @brief Get QFunctionContext field holding double precision values, read-only. 1495 For composite operators, the values correspond to the first sub-operator QFunctionContexts that has a matching `field_name`. 1496 1497 @param[in] op CeedOperator 1498 @param[in] field_label Label of field to get 1499 @param[out] num_values Number of values in the field label 1500 @param[out] values Pointer to context values 1501 1502 @return An error code: 0 - success, otherwise - failure 1503 1504 @ref User 1505 **/ 1506 int CeedOperatorContextGetDoubleRead(CeedOperator op, CeedContextFieldLabel field_label, size_t *num_values, const double **values) { 1507 return CeedOperatorContextGetGenericRead(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, num_values, values); 1508 } 1509 1510 /** 1511 @brief Restore QFunctionContext field holding double precision values, read-only. 1512 1513 @param[in] op CeedOperator 1514 @param[in] field_label Label of field to restore 1515 @param[out] values Pointer to context values 1516 1517 @return An error code: 0 - success, otherwise - failure 1518 1519 @ref User 1520 **/ 1521 int CeedOperatorContextRestoreDoubleRead(CeedOperator op, CeedContextFieldLabel field_label, const double **values) { 1522 return CeedOperatorContextRestoreGenericRead(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, values); 1523 } 1524 1525 /** 1526 @brief Set QFunctionContext field holding int32 values. 1527 For composite operators, the values are set in all sub-operator QFunctionContexts that have a matching `field_name`. 1528 1529 @param[in,out] op CeedOperator 1530 @param[in] field_label Label of field to set 1531 @param[in] values Values to set 1532 1533 @return An error code: 0 - success, otherwise - failure 1534 1535 @ref User 1536 **/ 1537 int CeedOperatorContextSetInt32(CeedOperator op, CeedContextFieldLabel field_label, int *values) { 1538 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_INT32, values); 1539 } 1540 1541 /** 1542 @brief Get QFunctionContext field holding int32 values, read-only. 1543 For composite operators, the values correspond to the first sub-operator QFunctionContexts that has a matching `field_name`. 1544 1545 @param[in] op CeedOperator 1546 @param[in] field_label Label of field to get 1547 @param[out] num_values Number of values in the field label 1548 @param[out] values Pointer to context values 1549 1550 @return An error code: 0 - success, otherwise - failure 1551 1552 @ref User 1553 **/ 1554 int CeedOperatorContextGetInt32Read(CeedOperator op, CeedContextFieldLabel field_label, size_t *num_values, const int **values) { 1555 return CeedOperatorContextGetGenericRead(op, field_label, CEED_CONTEXT_FIELD_INT32, num_values, values); 1556 } 1557 1558 /** 1559 @brief Restore QFunctionContext field holding int32 values, read-only. 1560 1561 @param[in] op CeedOperator 1562 @param[in] field_label Label of field to get 1563 @param[out] num_values Number of values in the field label 1564 @param[out] values Pointer to context values 1565 1566 @return An error code: 0 - success, otherwise - failure 1567 1568 @ref User 1569 **/ 1570 int CeedOperatorContextRestoreInt32Read(CeedOperator op, CeedContextFieldLabel field_label, const int **values) { 1571 return CeedOperatorContextRestoreGenericRead(op, field_label, CEED_CONTEXT_FIELD_INT32, values); 1572 } 1573 1574 /** 1575 @brief Apply CeedOperator to a vector 1576 1577 This computes the action of the operator on the specified (active) input, yielding its (active) output. 1578 All inputs and outputs must be specified using CeedOperatorSetField(). 1579 1580 Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 1581 1582 @param[in] op CeedOperator to apply 1583 @param[in] in CeedVector containing input state or @ref CEED_VECTOR_NONE if there are no active inputs 1584 @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 1585 outputs 1586 @param[in] request Address of CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE 1587 1588 @return An error code: 0 - success, otherwise - failure 1589 1590 @ref User 1591 **/ 1592 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, CeedRequest *request) { 1593 CeedCall(CeedOperatorCheckReady(op)); 1594 1595 if (op->num_elem) { 1596 // Standard Operator 1597 if (op->Apply) { 1598 CeedCall(op->Apply(op, in, out, request)); 1599 } else { 1600 // Zero all output vectors 1601 CeedQFunction qf = op->qf; 1602 for (CeedInt i = 0; i < qf->num_output_fields; i++) { 1603 CeedVector vec = op->output_fields[i]->vec; 1604 if (vec == CEED_VECTOR_ACTIVE) vec = out; 1605 if (vec != CEED_VECTOR_NONE) { 1606 CeedCall(CeedVectorSetValue(vec, 0.0)); 1607 } 1608 } 1609 // Apply 1610 CeedCall(op->ApplyAdd(op, in, out, request)); 1611 } 1612 } else if (op->is_composite) { 1613 // Composite Operator 1614 if (op->ApplyComposite) { 1615 CeedCall(op->ApplyComposite(op, in, out, request)); 1616 } else { 1617 CeedInt num_suboperators; 1618 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 1619 CeedOperator *sub_operators; 1620 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1621 1622 // Zero all output vectors 1623 if (out != CEED_VECTOR_NONE) { 1624 CeedCall(CeedVectorSetValue(out, 0.0)); 1625 } 1626 for (CeedInt i = 0; i < num_suboperators; i++) { 1627 for (CeedInt j = 0; j < sub_operators[i]->qf->num_output_fields; j++) { 1628 CeedVector vec = sub_operators[i]->output_fields[j]->vec; 1629 if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) { 1630 CeedCall(CeedVectorSetValue(vec, 0.0)); 1631 } 1632 } 1633 } 1634 // Apply 1635 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1636 CeedCall(CeedOperatorApplyAdd(op->sub_operators[i], in, out, request)); 1637 } 1638 } 1639 } 1640 return CEED_ERROR_SUCCESS; 1641 } 1642 1643 /** 1644 @brief Apply CeedOperator to a vector and add result to output vector 1645 1646 This computes the action of the operator on the specified (active) input, yielding its (active) output. 1647 All inputs and outputs must be specified using CeedOperatorSetField(). 1648 1649 @param[in] op CeedOperator to apply 1650 @param[in] in CeedVector containing input state or NULL if there are no active inputs 1651 @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 1652 @param[in] request Address of CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE 1653 1654 @return An error code: 0 - success, otherwise - failure 1655 1656 @ref User 1657 **/ 1658 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, CeedRequest *request) { 1659 CeedCall(CeedOperatorCheckReady(op)); 1660 1661 if (op->num_elem) { 1662 // Standard Operator 1663 CeedCall(op->ApplyAdd(op, in, out, request)); 1664 } else if (op->is_composite) { 1665 // Composite Operator 1666 if (op->ApplyAddComposite) { 1667 CeedCall(op->ApplyAddComposite(op, in, out, request)); 1668 } else { 1669 CeedInt num_suboperators; 1670 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 1671 CeedOperator *sub_operators; 1672 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1673 1674 for (CeedInt i = 0; i < num_suboperators; i++) { 1675 CeedCall(CeedOperatorApplyAdd(sub_operators[i], in, out, request)); 1676 } 1677 } 1678 } 1679 return CEED_ERROR_SUCCESS; 1680 } 1681 1682 /** 1683 @brief Destroy a CeedOperator 1684 1685 @param[in,out] op CeedOperator to destroy 1686 1687 @return An error code: 0 - success, otherwise - failure 1688 1689 @ref User 1690 **/ 1691 int CeedOperatorDestroy(CeedOperator *op) { 1692 if (!*op || --(*op)->ref_count > 0) return CEED_ERROR_SUCCESS; 1693 if ((*op)->Destroy) CeedCall((*op)->Destroy(*op)); 1694 CeedCall(CeedDestroy(&(*op)->ceed)); 1695 // Free fields 1696 for (CeedInt i = 0; i < (*op)->num_fields; i++) { 1697 if ((*op)->input_fields[i]) { 1698 if ((*op)->input_fields[i]->elem_rstr != CEED_ELEMRESTRICTION_NONE) { 1699 CeedCall(CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_rstr)); 1700 } 1701 if ((*op)->input_fields[i]->basis != CEED_BASIS_COLLOCATED) { 1702 CeedCall(CeedBasisDestroy(&(*op)->input_fields[i]->basis)); 1703 } 1704 if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE && (*op)->input_fields[i]->vec != CEED_VECTOR_NONE) { 1705 CeedCall(CeedVectorDestroy(&(*op)->input_fields[i]->vec)); 1706 } 1707 CeedCall(CeedFree(&(*op)->input_fields[i]->field_name)); 1708 CeedCall(CeedFree(&(*op)->input_fields[i])); 1709 } 1710 } 1711 for (CeedInt i = 0; i < (*op)->num_fields; i++) { 1712 if ((*op)->output_fields[i]) { 1713 CeedCall(CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_rstr)); 1714 if ((*op)->output_fields[i]->basis != CEED_BASIS_COLLOCATED) { 1715 CeedCall(CeedBasisDestroy(&(*op)->output_fields[i]->basis)); 1716 } 1717 if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE && (*op)->output_fields[i]->vec != CEED_VECTOR_NONE) { 1718 CeedCall(CeedVectorDestroy(&(*op)->output_fields[i]->vec)); 1719 } 1720 CeedCall(CeedFree(&(*op)->output_fields[i]->field_name)); 1721 CeedCall(CeedFree(&(*op)->output_fields[i])); 1722 } 1723 } 1724 // Destroy sub_operators 1725 for (CeedInt i = 0; i < (*op)->num_suboperators; i++) { 1726 if ((*op)->sub_operators[i]) { 1727 CeedCall(CeedOperatorDestroy(&(*op)->sub_operators[i])); 1728 } 1729 } 1730 CeedCall(CeedQFunctionDestroy(&(*op)->qf)); 1731 CeedCall(CeedQFunctionDestroy(&(*op)->dqf)); 1732 CeedCall(CeedQFunctionDestroy(&(*op)->dqfT)); 1733 // Destroy any composite labels 1734 for (CeedInt i = 0; i < (*op)->num_context_labels; i++) { 1735 CeedCall(CeedFree(&(*op)->context_labels[i]->sub_labels)); 1736 CeedCall(CeedFree(&(*op)->context_labels[i])); 1737 } 1738 CeedCall(CeedFree(&(*op)->context_labels)); 1739 1740 // Destroy fallback 1741 CeedCall(CeedOperatorDestroy(&(*op)->op_fallback)); 1742 1743 // Destroy assembly data 1744 CeedCall(CeedQFunctionAssemblyDataDestroy(&(*op)->qf_assembled)); 1745 CeedCall(CeedOperatorAssemblyDataDestroy(&(*op)->op_assembled)); 1746 1747 CeedCall(CeedFree(&(*op)->input_fields)); 1748 CeedCall(CeedFree(&(*op)->output_fields)); 1749 CeedCall(CeedFree(&(*op)->sub_operators)); 1750 CeedCall(CeedFree(&(*op)->name)); 1751 CeedCall(CeedFree(op)); 1752 return CEED_ERROR_SUCCESS; 1753 } 1754 1755 /// @} 1756