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