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