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