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