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, rstr_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, &rstr_num_comp)); 45 } 46 // Basis 47 CeedCheck((b == CEED_BASIS_NONE) == (eval_mode == CEED_EVAL_NONE), ceed, CEED_ERROR_INCOMPATIBLE, 48 "CEED_BASIS_NONE and CEED_EVAL_NONE must be used together."); 49 if (b != CEED_BASIS_NONE) { 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 || rstr_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], rstr_num_comp, num_comp); 57 } 58 // Field size 59 switch (eval_mode) { 60 case CEED_EVAL_NONE: 61 CeedCheck(size == rstr_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], rstr_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_NONE) fprintf(stream, "%s No 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_NONE, 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_NONE 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 CeedRestrictionType rstr_type; 643 644 CeedCall(CeedElemRestrictionGetType(r, &rstr_type)); 645 CeedCheck(rstr_type != CEED_RESTRICTION_POINTS, op->ceed, CEED_ERROR_UNSUPPORTED, 646 "CeedElemRestrictionAtPoints not supported for standard operator fields"); 647 } 648 649 if (b == CEED_BASIS_NONE) CeedCall(CeedElemRestrictionGetElementSize(r, &num_qpts)); 650 else CeedCall(CeedBasisGetNumQuadraturePoints(b, &num_qpts)); 651 CeedCheck(op->num_qpts == 0 || op->num_qpts == num_qpts, op->ceed, CEED_ERROR_DIMENSION, 652 "%s must correspond to the same number of quadrature points as previously added Bases. Found %" CeedInt_FMT 653 " quadrature points but expected %" CeedInt_FMT " quadrature points.", 654 b == CEED_BASIS_NONE ? "ElemRestriction" : "Basis", num_qpts, op->num_qpts); 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 680 CeedCall(CeedElemRestrictionGetLVectorSize(r, &l_size)); 681 if (is_input) { 682 if (op->input_size == -1) op->input_size = l_size; 683 CeedCheck(l_size == op->input_size, op->ceed, CEED_ERROR_INCOMPATIBLE, "LVector size %td does not match previous size %td", l_size, 684 op->input_size); 685 } else { 686 if (op->output_size == -1) op->output_size = l_size; 687 CeedCheck(l_size == op->output_size, op->ceed, CEED_ERROR_INCOMPATIBLE, "LVector size %td does not match previous size %td", l_size, 688 op->output_size); 689 } 690 } 691 692 CeedCall(CeedVectorReferenceCopy(v, &(*op_field)->vec)); 693 CeedCall(CeedElemRestrictionReferenceCopy(r, &(*op_field)->elem_rstr)); 694 if (r != CEED_ELEMRESTRICTION_NONE) { 695 op->num_elem = num_elem; 696 op->has_restriction = true; // Restriction set, but num_elem may be 0 697 } 698 CeedCall(CeedBasisReferenceCopy(b, &(*op_field)->basis)); 699 if (op->num_qpts == 0) CeedCall(CeedOperatorSetNumQuadraturePoints(op, num_qpts)); 700 701 op->num_fields += 1; 702 CeedCall(CeedStringAllocCopy(field_name, (char **)&(*op_field)->field_name)); 703 return CEED_ERROR_SUCCESS; 704 } 705 706 /** 707 @brief Get the CeedOperatorFields of a CeedOperator 708 709 Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 710 711 @param[in] op CeedOperator 712 @param[out] num_input_fields Variable to store number of input fields 713 @param[out] input_fields Variable to store input_fields 714 @param[out] num_output_fields Variable to store number of output fields 715 @param[out] output_fields Variable to store output_fields 716 717 @return An error code: 0 - success, otherwise - failure 718 719 @ref Advanced 720 **/ 721 int CeedOperatorGetFields(CeedOperator op, CeedInt *num_input_fields, CeedOperatorField **input_fields, CeedInt *num_output_fields, 722 CeedOperatorField **output_fields) { 723 CeedCheck(!op->is_composite, op->ceed, CEED_ERROR_MINOR, "Not defined for composite operator"); 724 CeedCall(CeedOperatorCheckReady(op)); 725 726 if (num_input_fields) *num_input_fields = op->qf->num_input_fields; 727 if (input_fields) *input_fields = op->input_fields; 728 if (num_output_fields) *num_output_fields = op->qf->num_output_fields; 729 if (output_fields) *output_fields = op->output_fields; 730 return CEED_ERROR_SUCCESS; 731 } 732 733 /** 734 @brief Get a CeedOperatorField of an CeedOperator from its name 735 736 Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 737 738 @param[in] op CeedOperator 739 @param[in] field_name Name of desired CeedOperatorField 740 @param[out] op_field CeedOperatorField corresponding to the name 741 742 @return An error code: 0 - success, otherwise - failure 743 744 @ref Advanced 745 **/ 746 int CeedOperatorGetFieldByName(CeedOperator op, const char *field_name, CeedOperatorField *op_field) { 747 char *name; 748 CeedInt num_input_fields, num_output_fields; 749 CeedOperatorField *input_fields, *output_fields; 750 751 CeedCall(CeedOperatorGetFields(op, &num_input_fields, &input_fields, &num_output_fields, &output_fields)); 752 for (CeedInt i = 0; i < num_input_fields; i++) { 753 CeedCall(CeedOperatorFieldGetName(input_fields[i], &name)); 754 if (!strcmp(name, field_name)) { 755 *op_field = input_fields[i]; 756 return CEED_ERROR_SUCCESS; 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 // LCOV_EXCL_START 767 bool has_name = op->name; 768 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 852 CeedCall(CeedOperatorGetActiveVectorLengths(sub_op, &input_size, &output_size)); 853 if (composite_op->input_size == -1) composite_op->input_size = input_size; 854 if (composite_op->output_size == -1) composite_op->output_size = output_size; 855 // Note, a size of -1 means no active vector restriction set, so no incompatibility 856 CeedCheck((input_size == -1 || input_size == composite_op->input_size) && (output_size == -1 || output_size == composite_op->output_size), 857 composite_op->ceed, CEED_ERROR_MAJOR, 858 "Sub-operators must have compatible dimensions; composite operator of shape (%td, %td) not compatible with sub-operator of " 859 "shape (%td, %td)", 860 composite_op->input_size, composite_op->output_size, input_size, output_size); 861 } 862 863 composite_op->sub_operators[composite_op->num_suboperators] = sub_op; 864 CeedCall(CeedOperatorReference(sub_op)); 865 composite_op->num_suboperators++; 866 return CEED_ERROR_SUCCESS; 867 } 868 869 /** 870 @brief Get the number of sub_operators associated with a CeedOperator 871 872 @param[in] op CeedOperator 873 @param[out] num_suboperators Variable to store number of sub_operators 874 875 @return An error code: 0 - success, otherwise - failure 876 877 @ref Backend 878 **/ 879 int CeedCompositeOperatorGetNumSub(CeedOperator op, CeedInt *num_suboperators) { 880 CeedCheck(op->is_composite, op->ceed, CEED_ERROR_MINOR, "Only defined for a composite operator"); 881 *num_suboperators = op->num_suboperators; 882 return CEED_ERROR_SUCCESS; 883 } 884 885 /** 886 @brief Get the list of sub_operators associated with a CeedOperator 887 888 @param op CeedOperator 889 @param[out] sub_operators Variable to store list of sub_operators 890 891 @return An error code: 0 - success, otherwise - failure 892 893 @ref Backend 894 **/ 895 int CeedCompositeOperatorGetSubList(CeedOperator op, CeedOperator **sub_operators) { 896 CeedCheck(op->is_composite, op->ceed, CEED_ERROR_MINOR, "Only defined for a composite operator"); 897 *sub_operators = op->sub_operators; 898 return CEED_ERROR_SUCCESS; 899 } 900 901 /** 902 @brief Check if a CeedOperator is ready to be used. 903 904 @param[in] op CeedOperator to check 905 906 @return An error code: 0 - success, otherwise - failure 907 908 @ref User 909 **/ 910 int CeedOperatorCheckReady(CeedOperator op) { 911 Ceed ceed; 912 913 CeedCall(CeedOperatorGetCeed(op, &ceed)); 914 915 if (op->is_interface_setup) return CEED_ERROR_SUCCESS; 916 917 CeedQFunction qf = op->qf; 918 if (op->is_composite) { 919 if (!op->num_suboperators) { 920 // Empty operator setup 921 op->input_size = 0; 922 op->output_size = 0; 923 } else { 924 for (CeedInt i = 0; i < op->num_suboperators; i++) { 925 CeedCall(CeedOperatorCheckReady(op->sub_operators[i])); 926 } 927 // Sub-operators could be modified after adding to composite operator 928 // Need to verify no lvec incompatibility from any changes 929 CeedSize input_size, output_size; 930 CeedCall(CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size)); 931 } 932 } else { 933 CeedCheck(op->num_fields > 0, ceed, CEED_ERROR_INCOMPLETE, "No operator fields set"); 934 CeedCheck(op->num_fields == qf->num_input_fields + qf->num_output_fields, ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set"); 935 CeedCheck(op->has_restriction, ceed, CEED_ERROR_INCOMPLETE, "At least one restriction required"); 936 CeedCheck(op->num_qpts > 0, ceed, CEED_ERROR_INCOMPLETE, 937 "At least one non-collocated basis is required or the number of quadrature points must be set"); 938 } 939 940 // Flag as immutable and ready 941 op->is_interface_setup = true; 942 if (op->qf && op->qf != CEED_QFUNCTION_NONE) op->qf->is_immutable = true; 943 if (op->dqf && op->dqf != CEED_QFUNCTION_NONE) op->dqf->is_immutable = true; 944 if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE) op->dqfT->is_immutable = true; 945 return CEED_ERROR_SUCCESS; 946 } 947 948 /** 949 @brief Get vector lengths for the active input and/or output vectors of a CeedOperator. 950 951 Note: Lengths of -1 indicate that the CeedOperator does not have an active input and/or output. 952 953 @param[in] op CeedOperator 954 @param[out] input_size Variable to store active input vector length, or NULL 955 @param[out] output_size Variable to store active output vector length, or NULL 956 957 @return An error code: 0 - success, otherwise - failure 958 959 @ref User 960 **/ 961 int CeedOperatorGetActiveVectorLengths(CeedOperator op, CeedSize *input_size, CeedSize *output_size) { 962 bool is_composite; 963 964 if (input_size) *input_size = op->input_size; 965 if (output_size) *output_size = op->output_size; 966 967 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 968 if (is_composite && (op->input_size == -1 || op->output_size == -1)) { 969 for (CeedInt i = 0; i < op->num_suboperators; i++) { 970 CeedSize sub_input_size, sub_output_size; 971 972 CeedCall(CeedOperatorGetActiveVectorLengths(op->sub_operators[i], &sub_input_size, &sub_output_size)); 973 if (op->input_size == -1) op->input_size = sub_input_size; 974 if (op->output_size == -1) op->output_size = sub_output_size; 975 // Note, a size of -1 means no active vector restriction set, so no incompatibility 976 CeedCheck((sub_input_size == -1 || sub_input_size == op->input_size) && (sub_output_size == -1 || sub_output_size == op->output_size), op->ceed, 977 CEED_ERROR_MAJOR, 978 "Sub-operators must have compatible dimensions; composite operator of shape (%td, %td) not compatible with sub-operator of " 979 "shape (%td, %td)", 980 op->input_size, op->output_size, input_size, output_size); 981 } 982 } 983 return CEED_ERROR_SUCCESS; 984 } 985 986 /** 987 @brief Set reuse of CeedQFunction data in CeedOperatorLinearAssemble* functions. 988 989 When `reuse_assembly_data = false` (default), the CeedQFunction associated with this CeedOperator is re-assembled every time a 990 `CeedOperatorLinearAssemble*` function is called. 991 When `reuse_assembly_data = true`, the CeedQFunction associated with this CeedOperator is reused between calls to 992 `CeedOperatorSetQFunctionAssemblyDataUpdated`. 993 994 @param[in] op CeedOperator 995 @param[in] reuse_assembly_data Boolean flag setting assembly data reuse 996 997 @return An error code: 0 - success, otherwise - failure 998 999 @ref Advanced 1000 **/ 1001 int CeedOperatorSetQFunctionAssemblyReuse(CeedOperator op, bool reuse_assembly_data) { 1002 bool is_composite; 1003 1004 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1005 if (is_composite) { 1006 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1007 CeedCall(CeedOperatorSetQFunctionAssemblyReuse(op->sub_operators[i], reuse_assembly_data)); 1008 } 1009 } else { 1010 CeedCall(CeedQFunctionAssemblyDataSetReuse(op->qf_assembled, reuse_assembly_data)); 1011 } 1012 return CEED_ERROR_SUCCESS; 1013 } 1014 1015 /** 1016 @brief Mark CeedQFunction data as updated and the CeedQFunction as requiring re-assembly. 1017 1018 @param[in] op CeedOperator 1019 @param[in] needs_data_update Boolean flag setting assembly data reuse 1020 1021 @return An error code: 0 - success, otherwise - failure 1022 1023 @ref Advanced 1024 **/ 1025 int CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(CeedOperator op, bool needs_data_update) { 1026 bool is_composite; 1027 1028 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1029 if (is_composite) { 1030 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1031 CeedCall(CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(op->sub_operators[i], needs_data_update)); 1032 } 1033 } else { 1034 CeedCall(CeedQFunctionAssemblyDataSetUpdateNeeded(op->qf_assembled, needs_data_update)); 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 CeedOperator"); 1054 CeedCheck(!op->is_immutable, op->ceed, CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable"); 1055 if (op->num_qpts > 0) { 1056 CeedWarn( 1057 "CeedOperatorSetNumQuadraturePoints will be removed from the libCEED interface in the next release.\n" 1058 "This function is redundant and you can safely remove any calls to this function without replacing them."); 1059 CeedCheck(num_qpts == op->num_qpts, op->ceed, CEED_ERROR_DIMENSION, "Different number of quadrature points already defined for the CeedOperator"); 1060 } 1061 op->num_qpts = num_qpts; 1062 return CEED_ERROR_SUCCESS; 1063 } 1064 1065 /** 1066 @brief Set name of CeedOperator for CeedOperatorView output 1067 1068 @param[in,out] op CeedOperator 1069 @param[in] name Name to set, or NULL to remove previously set name 1070 1071 @return An error code: 0 - success, otherwise - failure 1072 1073 @ref User 1074 **/ 1075 int CeedOperatorSetName(CeedOperator op, const char *name) { 1076 char *name_copy; 1077 size_t name_len = name ? strlen(name) : 0; 1078 1079 CeedCall(CeedFree(&op->name)); 1080 if (name_len > 0) { 1081 CeedCall(CeedCalloc(name_len + 1, &name_copy)); 1082 memcpy(name_copy, name, name_len); 1083 op->name = name_copy; 1084 } 1085 return CEED_ERROR_SUCCESS; 1086 } 1087 1088 /** 1089 @brief View a CeedOperator 1090 1091 @param[in] op CeedOperator to view 1092 @param[in] stream Stream to write; typically stdout/stderr or a file 1093 1094 @return Error code: 0 - success, otherwise - failure 1095 1096 @ref User 1097 **/ 1098 int CeedOperatorView(CeedOperator op, FILE *stream) { 1099 bool has_name = op->name; 1100 1101 if (op->is_composite) { 1102 fprintf(stream, "Composite CeedOperator%s%s\n", has_name ? " - " : "", has_name ? op->name : ""); 1103 1104 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1105 has_name = op->sub_operators[i]->name; 1106 fprintf(stream, " SubOperator %" CeedInt_FMT "%s%s:\n", i, has_name ? " - " : "", has_name ? op->sub_operators[i]->name : ""); 1107 CeedCall(CeedOperatorSingleView(op->sub_operators[i], 1, stream)); 1108 } 1109 } else { 1110 fprintf(stream, "CeedOperator%s%s\n", has_name ? " - " : "", has_name ? op->name : ""); 1111 CeedCall(CeedOperatorSingleView(op, 0, stream)); 1112 } 1113 return CEED_ERROR_SUCCESS; 1114 } 1115 1116 /** 1117 @brief Get the Ceed associated with a CeedOperator 1118 1119 @param[in] op CeedOperator 1120 @param[out] ceed Variable to store Ceed 1121 1122 @return An error code: 0 - success, otherwise - failure 1123 1124 @ref Advanced 1125 **/ 1126 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) { 1127 *ceed = op->ceed; 1128 return CEED_ERROR_SUCCESS; 1129 } 1130 1131 /** 1132 @brief Get the number of elements associated with a CeedOperator 1133 1134 @param[in] op CeedOperator 1135 @param[out] num_elem Variable to store number of elements 1136 1137 @return An error code: 0 - success, otherwise - failure 1138 1139 @ref Advanced 1140 **/ 1141 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) { 1142 CeedCheck(!op->is_composite, op->ceed, CEED_ERROR_MINOR, "Not defined for composite operator"); 1143 *num_elem = op->num_elem; 1144 return CEED_ERROR_SUCCESS; 1145 } 1146 1147 /** 1148 @brief Get the number of quadrature points associated with a CeedOperator 1149 1150 @param[in] op CeedOperator 1151 @param[out] num_qpts Variable to store vector number of quadrature points 1152 1153 @return An error code: 0 - success, otherwise - failure 1154 1155 @ref Advanced 1156 **/ 1157 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) { 1158 CeedCheck(!op->is_composite, op->ceed, CEED_ERROR_MINOR, "Not defined for composite operator"); 1159 *num_qpts = op->num_qpts; 1160 return CEED_ERROR_SUCCESS; 1161 } 1162 1163 /** 1164 @brief Estimate number of FLOPs required to apply CeedOperator on the active vector 1165 1166 @param[in] op CeedOperator to estimate FLOPs for 1167 @param[out] flops Address of variable to hold FLOPs estimate 1168 1169 @ref Backend 1170 **/ 1171 int CeedOperatorGetFlopsEstimate(CeedOperator op, CeedSize *flops) { 1172 bool is_composite; 1173 1174 CeedCall(CeedOperatorCheckReady(op)); 1175 1176 *flops = 0; 1177 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1178 if (is_composite) { 1179 CeedInt num_suboperators; 1180 1181 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 1182 CeedOperator *sub_operators; 1183 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1184 1185 // FLOPs for each suboperator 1186 for (CeedInt i = 0; i < num_suboperators; i++) { 1187 CeedSize suboperator_flops; 1188 1189 CeedCall(CeedOperatorGetFlopsEstimate(sub_operators[i], &suboperator_flops)); 1190 *flops += suboperator_flops; 1191 } 1192 } else { 1193 CeedInt num_input_fields, num_output_fields, num_elem = 0; 1194 CeedOperatorField *input_fields, *output_fields; 1195 1196 CeedCall(CeedOperatorGetFields(op, &num_input_fields, &input_fields, &num_output_fields, &output_fields)); 1197 CeedCall(CeedOperatorGetNumElements(op, &num_elem)); 1198 1199 // Input FLOPs 1200 for (CeedInt i = 0; i < num_input_fields; i++) { 1201 if (input_fields[i]->vec == CEED_VECTOR_ACTIVE) { 1202 CeedSize rstr_flops, basis_flops; 1203 1204 CeedCall(CeedElemRestrictionGetFlopsEstimate(input_fields[i]->elem_rstr, CEED_NOTRANSPOSE, &rstr_flops)); 1205 *flops += rstr_flops; 1206 CeedCall(CeedBasisGetFlopsEstimate(input_fields[i]->basis, CEED_NOTRANSPOSE, op->qf->input_fields[i]->eval_mode, &basis_flops)); 1207 *flops += basis_flops * num_elem; 1208 } 1209 } 1210 // QF FLOPs 1211 { 1212 CeedInt num_qpts; 1213 CeedSize qf_flops; 1214 1215 CeedCall(CeedOperatorGetNumQuadraturePoints(op, &num_qpts)); 1216 CeedCall(CeedQFunctionGetFlopsEstimate(op->qf, &qf_flops)); 1217 *flops += num_elem * num_qpts * qf_flops; 1218 } 1219 1220 // Output FLOPs 1221 for (CeedInt i = 0; i < num_output_fields; i++) { 1222 if (output_fields[i]->vec == CEED_VECTOR_ACTIVE) { 1223 CeedSize rstr_flops, basis_flops; 1224 1225 CeedCall(CeedElemRestrictionGetFlopsEstimate(output_fields[i]->elem_rstr, CEED_TRANSPOSE, &rstr_flops)); 1226 *flops += rstr_flops; 1227 CeedCall(CeedBasisGetFlopsEstimate(output_fields[i]->basis, CEED_TRANSPOSE, op->qf->output_fields[i]->eval_mode, &basis_flops)); 1228 *flops += basis_flops * num_elem; 1229 } 1230 } 1231 } 1232 return CEED_ERROR_SUCCESS; 1233 } 1234 1235 /** 1236 @brief Get CeedQFunction global context for a CeedOperator. 1237 1238 The caller is responsible for destroying `ctx` returned from this function via `CeedQFunctionContextDestroy()`. 1239 1240 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. 1241 This CeedQFunctionContext will be destroyed if `ctx` is the only reference to this CeedQFunctionContext. 1242 1243 @param[in] op CeedOperator 1244 @param[out] ctx Variable to store CeedQFunctionContext 1245 1246 @return An error code: 0 - success, otherwise - failure 1247 1248 @ref Advanced 1249 **/ 1250 int CeedOperatorGetContext(CeedOperator op, CeedQFunctionContext *ctx) { 1251 CeedCheck(!op->is_composite, op->ceed, CEED_ERROR_INCOMPATIBLE, "Cannot retrieve QFunctionContext for composite operator"); 1252 if (op->qf->ctx) CeedCall(CeedQFunctionContextReferenceCopy(op->qf->ctx, ctx)); 1253 else *ctx = NULL; 1254 return CEED_ERROR_SUCCESS; 1255 } 1256 1257 /** 1258 @brief Get label for a registered QFunctionContext field, or `NULL` if no field has been registered with this `field_name`. 1259 1260 Fields are registered via `CeedQFunctionContextRegister*()` functions (eg. `CeedQFunctionContextRegisterDouble()`). 1261 1262 @param[in] op CeedOperator 1263 @param[in] field_name Name of field to retrieve label 1264 @param[out] field_label Variable to field label 1265 1266 @return An error code: 0 - success, otherwise - failure 1267 1268 @ref User 1269 **/ 1270 int CeedOperatorGetContextFieldLabel(CeedOperator op, const char *field_name, CeedContextFieldLabel *field_label) { 1271 bool is_composite, field_found = false; 1272 1273 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1274 1275 if (is_composite) { 1276 // Composite operator 1277 // -- Check if composite label already created 1278 for (CeedInt i = 0; i < op->num_context_labels; i++) { 1279 if (!strcmp(op->context_labels[i]->name, field_name)) { 1280 *field_label = op->context_labels[i]; 1281 return CEED_ERROR_SUCCESS; 1282 } 1283 } 1284 1285 // -- Create composite label if needed 1286 CeedInt num_sub; 1287 CeedOperator *sub_operators; 1288 CeedContextFieldLabel new_field_label; 1289 1290 CeedCall(CeedCalloc(1, &new_field_label)); 1291 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_sub)); 1292 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1293 CeedCall(CeedCalloc(num_sub, &new_field_label->sub_labels)); 1294 new_field_label->num_sub_labels = num_sub; 1295 1296 for (CeedInt i = 0; i < num_sub; i++) { 1297 if (sub_operators[i]->qf->ctx) { 1298 CeedContextFieldLabel new_field_label_i; 1299 1300 CeedCall(CeedQFunctionContextGetFieldLabel(sub_operators[i]->qf->ctx, field_name, &new_field_label_i)); 1301 if (new_field_label_i) { 1302 field_found = true; 1303 new_field_label->sub_labels[i] = new_field_label_i; 1304 new_field_label->name = new_field_label_i->name; 1305 new_field_label->description = new_field_label_i->description; 1306 if (new_field_label->type && new_field_label->type != new_field_label_i->type) { 1307 // LCOV_EXCL_START 1308 CeedCall(CeedFree(&new_field_label)); 1309 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, "Incompatible field types on sub-operator contexts. %s != %s", 1310 CeedContextFieldTypes[new_field_label->type], CeedContextFieldTypes[new_field_label_i->type]); 1311 // LCOV_EXCL_STOP 1312 } else { 1313 new_field_label->type = new_field_label_i->type; 1314 } 1315 if (new_field_label->num_values != 0 && new_field_label->num_values != new_field_label_i->num_values) { 1316 // LCOV_EXCL_START 1317 CeedCall(CeedFree(&new_field_label)); 1318 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, "Incompatible field number of values on sub-operator contexts. %ld != %ld", 1319 new_field_label->num_values, new_field_label_i->num_values); 1320 // LCOV_EXCL_STOP 1321 } else { 1322 new_field_label->num_values = new_field_label_i->num_values; 1323 } 1324 } 1325 } 1326 } 1327 // -- Cleanup if field was found 1328 if (field_found) { 1329 *field_label = new_field_label; 1330 } else { 1331 // LCOV_EXCL_START 1332 CeedCall(CeedFree(&new_field_label->sub_labels)); 1333 CeedCall(CeedFree(&new_field_label)); 1334 *field_label = NULL; 1335 // LCOV_EXCL_STOP 1336 } 1337 } else { 1338 // Single, non-composite operator 1339 if (op->qf->ctx) { 1340 CeedCall(CeedQFunctionContextGetFieldLabel(op->qf->ctx, field_name, field_label)); 1341 } else { 1342 *field_label = NULL; 1343 } 1344 } 1345 1346 // Set label in operator 1347 if (*field_label) { 1348 (*field_label)->from_op = true; 1349 1350 // Move new composite label to operator 1351 if (op->num_context_labels == 0) { 1352 CeedCall(CeedCalloc(1, &op->context_labels)); 1353 op->max_context_labels = 1; 1354 } else if (op->num_context_labels == op->max_context_labels) { 1355 CeedCall(CeedRealloc(2 * op->num_context_labels, &op->context_labels)); 1356 op->max_context_labels *= 2; 1357 } 1358 op->context_labels[op->num_context_labels] = *field_label; 1359 op->num_context_labels++; 1360 } 1361 return CEED_ERROR_SUCCESS; 1362 } 1363 1364 /** 1365 @brief Set QFunctionContext field holding double precision values. 1366 1367 For composite operators, the values are set in all sub-operator QFunctionContexts that have a matching `field_name`. 1368 1369 @param[in,out] op CeedOperator 1370 @param[in] field_label Label of field to set 1371 @param[in] values Values to set 1372 1373 @return An error code: 0 - success, otherwise - failure 1374 1375 @ref User 1376 **/ 1377 int CeedOperatorSetContextDouble(CeedOperator op, CeedContextFieldLabel field_label, double *values) { 1378 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, values); 1379 } 1380 1381 /** 1382 @brief Get QFunctionContext field holding double precision values, read-only. 1383 1384 For composite operators, the values correspond to the first sub-operator QFunctionContexts that has a matching `field_name`. 1385 1386 @param[in] op CeedOperator 1387 @param[in] field_label Label of field to get 1388 @param[out] num_values Number of values in the field label 1389 @param[out] values Pointer to context values 1390 1391 @return An error code: 0 - success, otherwise - failure 1392 1393 @ref User 1394 **/ 1395 int CeedOperatorGetContextDoubleRead(CeedOperator op, CeedContextFieldLabel field_label, size_t *num_values, const double **values) { 1396 return CeedOperatorContextGetGenericRead(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, num_values, values); 1397 } 1398 1399 /** 1400 @brief Restore QFunctionContext field holding double precision values, read-only. 1401 1402 @param[in] op CeedOperator 1403 @param[in] field_label Label of field to restore 1404 @param[out] values Pointer to context values 1405 1406 @return An error code: 0 - success, otherwise - failure 1407 1408 @ref User 1409 **/ 1410 int CeedOperatorRestoreContextDoubleRead(CeedOperator op, CeedContextFieldLabel field_label, const double **values) { 1411 return CeedOperatorContextRestoreGenericRead(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, values); 1412 } 1413 1414 /** 1415 @brief Set QFunctionContext field holding int32 values. 1416 1417 For composite operators, the values are set in all sub-operator QFunctionContexts that have a matching `field_name`. 1418 1419 @param[in,out] op CeedOperator 1420 @param[in] field_label Label of field to set 1421 @param[in] values Values to set 1422 1423 @return An error code: 0 - success, otherwise - failure 1424 1425 @ref User 1426 **/ 1427 int CeedOperatorSetContextInt32(CeedOperator op, CeedContextFieldLabel field_label, int *values) { 1428 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_INT32, values); 1429 } 1430 1431 /** 1432 @brief Get QFunctionContext field holding int32 values, read-only. 1433 1434 For composite operators, the values correspond to the first sub-operator QFunctionContexts that has a matching `field_name`. 1435 1436 @param[in] op CeedOperator 1437 @param[in] field_label Label of field to get 1438 @param[out] num_values Number of int32 values in `values` 1439 @param[out] values Pointer to context values 1440 1441 @return An error code: 0 - success, otherwise - failure 1442 1443 @ref User 1444 **/ 1445 int CeedOperatorGetContextInt32Read(CeedOperator op, CeedContextFieldLabel field_label, size_t *num_values, const int **values) { 1446 return CeedOperatorContextGetGenericRead(op, field_label, CEED_CONTEXT_FIELD_INT32, num_values, values); 1447 } 1448 1449 /** 1450 @brief Restore QFunctionContext field holding int32 values, read-only. 1451 1452 @param[in] op CeedOperator 1453 @param[in] field_label Label of field to get 1454 @param[out] values Pointer to context values 1455 1456 @return An error code: 0 - success, otherwise - failure 1457 1458 @ref User 1459 **/ 1460 int CeedOperatorRestoreContextInt32Read(CeedOperator op, CeedContextFieldLabel field_label, const int **values) { 1461 return CeedOperatorContextRestoreGenericRead(op, field_label, CEED_CONTEXT_FIELD_INT32, values); 1462 } 1463 1464 /** 1465 @brief Apply CeedOperator to a vector 1466 1467 This computes the action of the operator on the specified (active) input, yielding its (active) output. 1468 All inputs and outputs must be specified using CeedOperatorSetField(). 1469 1470 Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 1471 1472 @param[in] op CeedOperator to apply 1473 @param[in] in CeedVector containing input state or @ref CEED_VECTOR_NONE if there are no active inputs 1474 @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 1475 active outputs 1476 @param[in] request Address of CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE 1477 1478 @return An error code: 0 - success, otherwise - failure 1479 1480 @ref User 1481 **/ 1482 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, CeedRequest *request) { 1483 CeedCall(CeedOperatorCheckReady(op)); 1484 1485 if (op->is_composite) { 1486 // Composite Operator 1487 if (op->ApplyComposite) { 1488 CeedCall(op->ApplyComposite(op, in, out, request)); 1489 } else { 1490 CeedInt num_suboperators; 1491 CeedOperator *sub_operators; 1492 1493 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 1494 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1495 1496 // Zero all output vectors 1497 if (out != CEED_VECTOR_NONE) CeedCall(CeedVectorSetValue(out, 0.0)); 1498 for (CeedInt i = 0; i < num_suboperators; i++) { 1499 for (CeedInt j = 0; j < sub_operators[i]->qf->num_output_fields; j++) { 1500 CeedVector vec = sub_operators[i]->output_fields[j]->vec; 1501 1502 if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) { 1503 CeedCall(CeedVectorSetValue(vec, 0.0)); 1504 } 1505 } 1506 } 1507 // Apply 1508 for (CeedInt i = 0; i < num_suboperators; i++) { 1509 CeedCall(CeedOperatorApplyAdd(sub_operators[i], in, out, request)); 1510 } 1511 } 1512 } else { 1513 // Standard Operator 1514 if (op->Apply) { 1515 CeedCall(op->Apply(op, in, out, request)); 1516 } else { 1517 // Zero all output vectors 1518 CeedQFunction qf = op->qf; 1519 1520 for (CeedInt i = 0; i < qf->num_output_fields; i++) { 1521 CeedVector vec = op->output_fields[i]->vec; 1522 1523 if (vec == CEED_VECTOR_ACTIVE) vec = out; 1524 if (vec != CEED_VECTOR_NONE) CeedCall(CeedVectorSetValue(vec, 0.0)); 1525 } 1526 // Apply 1527 if (op->num_elem) CeedCall(op->ApplyAdd(op, in, out, request)); 1528 } 1529 } 1530 return CEED_ERROR_SUCCESS; 1531 } 1532 1533 /** 1534 @brief Apply CeedOperator to a vector and add result to output vector 1535 1536 This computes the action of the operator on the specified (active) input, yielding its (active) output. 1537 All inputs and outputs must be specified using CeedOperatorSetField(). 1538 1539 @param[in] op CeedOperator to apply 1540 @param[in] in CeedVector containing input state or NULL if there are no active inputs 1541 @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 1542 @param[in] request Address of CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE 1543 1544 @return An error code: 0 - success, otherwise - failure 1545 1546 @ref User 1547 **/ 1548 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, CeedRequest *request) { 1549 CeedCall(CeedOperatorCheckReady(op)); 1550 1551 if (op->is_composite) { 1552 // Composite Operator 1553 if (op->ApplyAddComposite) { 1554 CeedCall(op->ApplyAddComposite(op, in, out, request)); 1555 } else { 1556 CeedInt num_suboperators; 1557 CeedOperator *sub_operators; 1558 1559 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 1560 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1561 for (CeedInt i = 0; i < num_suboperators; i++) { 1562 CeedCall(CeedOperatorApplyAdd(sub_operators[i], in, out, request)); 1563 } 1564 } 1565 } else if (op->num_elem) { 1566 // Standard Operator 1567 CeedCall(op->ApplyAdd(op, in, out, request)); 1568 } 1569 return CEED_ERROR_SUCCESS; 1570 } 1571 1572 /** 1573 @brief Destroy a CeedOperator 1574 1575 @param[in,out] op CeedOperator to destroy 1576 1577 @return An error code: 0 - success, otherwise - failure 1578 1579 @ref User 1580 **/ 1581 int CeedOperatorDestroy(CeedOperator *op) { 1582 if (!*op || --(*op)->ref_count > 0) { 1583 *op = NULL; 1584 return CEED_ERROR_SUCCESS; 1585 } 1586 if ((*op)->Destroy) CeedCall((*op)->Destroy(*op)); 1587 CeedCall(CeedDestroy(&(*op)->ceed)); 1588 // Free fields 1589 for (CeedInt i = 0; i < (*op)->num_fields; i++) { 1590 if ((*op)->input_fields[i]) { 1591 if ((*op)->input_fields[i]->elem_rstr != CEED_ELEMRESTRICTION_NONE) { 1592 CeedCall(CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_rstr)); 1593 } 1594 if ((*op)->input_fields[i]->basis != CEED_BASIS_NONE) { 1595 CeedCall(CeedBasisDestroy(&(*op)->input_fields[i]->basis)); 1596 } 1597 if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE && (*op)->input_fields[i]->vec != CEED_VECTOR_NONE) { 1598 CeedCall(CeedVectorDestroy(&(*op)->input_fields[i]->vec)); 1599 } 1600 CeedCall(CeedFree(&(*op)->input_fields[i]->field_name)); 1601 CeedCall(CeedFree(&(*op)->input_fields[i])); 1602 } 1603 } 1604 for (CeedInt i = 0; i < (*op)->num_fields; i++) { 1605 if ((*op)->output_fields[i]) { 1606 CeedCall(CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_rstr)); 1607 if ((*op)->output_fields[i]->basis != CEED_BASIS_NONE) { 1608 CeedCall(CeedBasisDestroy(&(*op)->output_fields[i]->basis)); 1609 } 1610 if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE && (*op)->output_fields[i]->vec != CEED_VECTOR_NONE) { 1611 CeedCall(CeedVectorDestroy(&(*op)->output_fields[i]->vec)); 1612 } 1613 CeedCall(CeedFree(&(*op)->output_fields[i]->field_name)); 1614 CeedCall(CeedFree(&(*op)->output_fields[i])); 1615 } 1616 } 1617 // Destroy sub_operators 1618 for (CeedInt i = 0; i < (*op)->num_suboperators; i++) { 1619 if ((*op)->sub_operators[i]) { 1620 CeedCall(CeedOperatorDestroy(&(*op)->sub_operators[i])); 1621 } 1622 } 1623 CeedCall(CeedQFunctionDestroy(&(*op)->qf)); 1624 CeedCall(CeedQFunctionDestroy(&(*op)->dqf)); 1625 CeedCall(CeedQFunctionDestroy(&(*op)->dqfT)); 1626 // Destroy any composite labels 1627 if ((*op)->is_composite) { 1628 for (CeedInt i = 0; i < (*op)->num_context_labels; i++) { 1629 CeedCall(CeedFree(&(*op)->context_labels[i]->sub_labels)); 1630 CeedCall(CeedFree(&(*op)->context_labels[i])); 1631 } 1632 } 1633 CeedCall(CeedFree(&(*op)->context_labels)); 1634 1635 // Destroy fallback 1636 CeedCall(CeedOperatorDestroy(&(*op)->op_fallback)); 1637 1638 // Destroy assembly data 1639 CeedCall(CeedQFunctionAssemblyDataDestroy(&(*op)->qf_assembled)); 1640 CeedCall(CeedOperatorAssemblyDataDestroy(&(*op)->op_assembled)); 1641 1642 CeedCall(CeedFree(&(*op)->input_fields)); 1643 CeedCall(CeedFree(&(*op)->output_fields)); 1644 CeedCall(CeedFree(&(*op)->sub_operators)); 1645 CeedCall(CeedFree(&(*op)->name)); 1646 CeedCall(CeedFree(op)); 1647 return CEED_ERROR_SUCCESS; 1648 } 1649 1650 /// @} 1651