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 if (op->num_qpts == 0) CeedCall(CeedOperatorSetNumQuadraturePoints(op, num_qpts)); 761 762 op->num_fields += 1; 763 CeedCall(CeedStringAllocCopy(field_name, (char **)&(*op_field)->field_name)); 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 the number of quadrature points associated with a CeedOperator. 1102 1103 This should be used when creating a CeedOperator where every field has a collocated basis. 1104 This function cannot be used for composite CeedOperators. 1105 1106 @param[in,out] op CeedOperator 1107 @param[in] num_qpts Number of quadrature points to set 1108 1109 @return An error code: 0 - success, otherwise - failure 1110 1111 @ref Advanced 1112 **/ 1113 int CeedOperatorSetNumQuadraturePoints(CeedOperator op, CeedInt num_qpts) { 1114 CeedCheck(!op->is_composite, op->ceed, CEED_ERROR_MINOR, "Not defined for composite CeedOperator"); 1115 CeedCheck(!op->is_immutable, op->ceed, CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable"); 1116 if (op->num_qpts > 0) { 1117 CeedWarn( 1118 "CeedOperatorSetNumQuadraturePoints will be removed from the libCEED interface in the next release.\n" 1119 "This function is redundant and you can safely remove any calls to this function without replacing them."); 1120 CeedCheck(num_qpts == op->num_qpts, op->ceed, CEED_ERROR_DIMENSION, "Different number of quadrature points already defined for the CeedOperator"); 1121 } 1122 op->num_qpts = num_qpts; 1123 return CEED_ERROR_SUCCESS; 1124 } 1125 1126 /** 1127 @brief Set name of CeedOperator for CeedOperatorView output 1128 1129 @param[in,out] op CeedOperator 1130 @param[in] name Name to set, or NULL to remove previously set name 1131 1132 @return An error code: 0 - success, otherwise - failure 1133 1134 @ref User 1135 **/ 1136 int CeedOperatorSetName(CeedOperator op, const char *name) { 1137 char *name_copy; 1138 size_t name_len = name ? strlen(name) : 0; 1139 1140 CeedCall(CeedFree(&op->name)); 1141 if (name_len > 0) { 1142 CeedCall(CeedCalloc(name_len + 1, &name_copy)); 1143 memcpy(name_copy, name, name_len); 1144 op->name = name_copy; 1145 } 1146 return CEED_ERROR_SUCCESS; 1147 } 1148 1149 /** 1150 @brief View a CeedOperator 1151 1152 @param[in] op CeedOperator to view 1153 @param[in] stream Stream to write; typically stdout/stderr or a file 1154 1155 @return Error code: 0 - success, otherwise - failure 1156 1157 @ref User 1158 **/ 1159 int CeedOperatorView(CeedOperator op, FILE *stream) { 1160 bool has_name = op->name; 1161 1162 if (op->is_composite) { 1163 fprintf(stream, "Composite CeedOperator%s%s\n", has_name ? " - " : "", has_name ? op->name : ""); 1164 1165 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1166 has_name = op->sub_operators[i]->name; 1167 fprintf(stream, " SubOperator %" CeedInt_FMT "%s%s:\n", i, has_name ? " - " : "", has_name ? op->sub_operators[i]->name : ""); 1168 CeedCall(CeedOperatorSingleView(op->sub_operators[i], 1, stream)); 1169 } 1170 } else { 1171 fprintf(stream, "CeedOperator%s%s\n", has_name ? " - " : "", has_name ? op->name : ""); 1172 CeedCall(CeedOperatorSingleView(op, 0, stream)); 1173 } 1174 return CEED_ERROR_SUCCESS; 1175 } 1176 1177 /** 1178 @brief Get the Ceed associated with a CeedOperator 1179 1180 @param[in] op CeedOperator 1181 @param[out] ceed Variable to store Ceed 1182 1183 @return An error code: 0 - success, otherwise - failure 1184 1185 @ref Advanced 1186 **/ 1187 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) { 1188 *ceed = op->ceed; 1189 return CEED_ERROR_SUCCESS; 1190 } 1191 1192 /** 1193 @brief Get the number of elements associated with a CeedOperator 1194 1195 @param[in] op CeedOperator 1196 @param[out] num_elem Variable to store number of elements 1197 1198 @return An error code: 0 - success, otherwise - failure 1199 1200 @ref Advanced 1201 **/ 1202 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) { 1203 CeedCheck(!op->is_composite, op->ceed, CEED_ERROR_MINOR, "Not defined for composite operator"); 1204 *num_elem = op->num_elem; 1205 return CEED_ERROR_SUCCESS; 1206 } 1207 1208 /** 1209 @brief Get the number of quadrature points associated with a CeedOperator 1210 1211 @param[in] op CeedOperator 1212 @param[out] num_qpts Variable to store vector number of quadrature points 1213 1214 @return An error code: 0 - success, otherwise - failure 1215 1216 @ref Advanced 1217 **/ 1218 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) { 1219 CeedCheck(!op->is_composite, op->ceed, CEED_ERROR_MINOR, "Not defined for composite operator"); 1220 *num_qpts = op->num_qpts; 1221 return CEED_ERROR_SUCCESS; 1222 } 1223 1224 /** 1225 @brief Estimate number of FLOPs required to apply CeedOperator on the active vector 1226 1227 @param[in] op CeedOperator to estimate FLOPs for 1228 @param[out] flops Address of variable to hold FLOPs estimate 1229 1230 @ref Backend 1231 **/ 1232 int CeedOperatorGetFlopsEstimate(CeedOperator op, CeedSize *flops) { 1233 bool is_composite; 1234 1235 CeedCall(CeedOperatorCheckReady(op)); 1236 1237 *flops = 0; 1238 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1239 if (is_composite) { 1240 CeedInt num_suboperators; 1241 1242 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 1243 CeedOperator *sub_operators; 1244 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1245 1246 // FLOPs for each suboperator 1247 for (CeedInt i = 0; i < num_suboperators; i++) { 1248 CeedSize suboperator_flops; 1249 1250 CeedCall(CeedOperatorGetFlopsEstimate(sub_operators[i], &suboperator_flops)); 1251 *flops += suboperator_flops; 1252 } 1253 } else { 1254 CeedInt num_input_fields, num_output_fields, num_elem = 0; 1255 CeedOperatorField *input_fields, *output_fields; 1256 1257 CeedCall(CeedOperatorGetFields(op, &num_input_fields, &input_fields, &num_output_fields, &output_fields)); 1258 CeedCall(CeedOperatorGetNumElements(op, &num_elem)); 1259 1260 // Input FLOPs 1261 for (CeedInt i = 0; i < num_input_fields; i++) { 1262 if (input_fields[i]->vec == CEED_VECTOR_ACTIVE) { 1263 CeedSize rstr_flops, basis_flops; 1264 1265 CeedCall(CeedElemRestrictionGetFlopsEstimate(input_fields[i]->elem_rstr, CEED_NOTRANSPOSE, &rstr_flops)); 1266 *flops += rstr_flops; 1267 CeedCall(CeedBasisGetFlopsEstimate(input_fields[i]->basis, CEED_NOTRANSPOSE, op->qf->input_fields[i]->eval_mode, &basis_flops)); 1268 *flops += basis_flops * num_elem; 1269 } 1270 } 1271 // QF FLOPs 1272 { 1273 CeedInt num_qpts; 1274 CeedSize qf_flops; 1275 1276 CeedCall(CeedOperatorGetNumQuadraturePoints(op, &num_qpts)); 1277 CeedCall(CeedQFunctionGetFlopsEstimate(op->qf, &qf_flops)); 1278 *flops += num_elem * num_qpts * qf_flops; 1279 } 1280 1281 // Output FLOPs 1282 for (CeedInt i = 0; i < num_output_fields; i++) { 1283 if (output_fields[i]->vec == CEED_VECTOR_ACTIVE) { 1284 CeedSize rstr_flops, basis_flops; 1285 1286 CeedCall(CeedElemRestrictionGetFlopsEstimate(output_fields[i]->elem_rstr, CEED_TRANSPOSE, &rstr_flops)); 1287 *flops += rstr_flops; 1288 CeedCall(CeedBasisGetFlopsEstimate(output_fields[i]->basis, CEED_TRANSPOSE, op->qf->output_fields[i]->eval_mode, &basis_flops)); 1289 *flops += basis_flops * num_elem; 1290 } 1291 } 1292 } 1293 return CEED_ERROR_SUCCESS; 1294 } 1295 1296 /** 1297 @brief Get CeedQFunction global context for a CeedOperator. 1298 1299 The caller is responsible for destroying `ctx` returned from this function via `CeedQFunctionContextDestroy()`. 1300 1301 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. 1302 This CeedQFunctionContext will be destroyed if `ctx` is the only reference to this CeedQFunctionContext. 1303 1304 @param[in] op CeedOperator 1305 @param[out] ctx Variable to store CeedQFunctionContext 1306 1307 @return An error code: 0 - success, otherwise - failure 1308 1309 @ref Advanced 1310 **/ 1311 int CeedOperatorGetContext(CeedOperator op, CeedQFunctionContext *ctx) { 1312 CeedCheck(!op->is_composite, op->ceed, CEED_ERROR_INCOMPATIBLE, "Cannot retrieve QFunctionContext for composite operator"); 1313 if (op->qf->ctx) CeedCall(CeedQFunctionContextReferenceCopy(op->qf->ctx, ctx)); 1314 else *ctx = NULL; 1315 return CEED_ERROR_SUCCESS; 1316 } 1317 1318 /** 1319 @brief Get label for a registered QFunctionContext field, or `NULL` if no field has been registered with this `field_name`. 1320 1321 Fields are registered via `CeedQFunctionContextRegister*()` functions (eg. `CeedQFunctionContextRegisterDouble()`). 1322 1323 @param[in] op CeedOperator 1324 @param[in] field_name Name of field to retrieve label 1325 @param[out] field_label Variable to field label 1326 1327 @return An error code: 0 - success, otherwise - failure 1328 1329 @ref User 1330 **/ 1331 int CeedOperatorGetContextFieldLabel(CeedOperator op, const char *field_name, CeedContextFieldLabel *field_label) { 1332 bool is_composite, field_found = false; 1333 1334 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1335 1336 if (is_composite) { 1337 // Composite operator 1338 // -- Check if composite label already created 1339 for (CeedInt i = 0; i < op->num_context_labels; i++) { 1340 if (!strcmp(op->context_labels[i]->name, field_name)) { 1341 *field_label = op->context_labels[i]; 1342 return CEED_ERROR_SUCCESS; 1343 } 1344 } 1345 1346 // -- Create composite label if needed 1347 CeedInt num_sub; 1348 CeedOperator *sub_operators; 1349 CeedContextFieldLabel new_field_label; 1350 1351 CeedCall(CeedCalloc(1, &new_field_label)); 1352 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_sub)); 1353 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1354 CeedCall(CeedCalloc(num_sub, &new_field_label->sub_labels)); 1355 new_field_label->num_sub_labels = num_sub; 1356 1357 for (CeedInt i = 0; i < num_sub; i++) { 1358 if (sub_operators[i]->qf->ctx) { 1359 CeedContextFieldLabel new_field_label_i; 1360 1361 CeedCall(CeedQFunctionContextGetFieldLabel(sub_operators[i]->qf->ctx, field_name, &new_field_label_i)); 1362 if (new_field_label_i) { 1363 field_found = true; 1364 new_field_label->sub_labels[i] = new_field_label_i; 1365 new_field_label->name = new_field_label_i->name; 1366 new_field_label->description = new_field_label_i->description; 1367 if (new_field_label->type && new_field_label->type != new_field_label_i->type) { 1368 // LCOV_EXCL_START 1369 CeedCall(CeedFree(&new_field_label)); 1370 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, "Incompatible field types on sub-operator contexts. %s != %s", 1371 CeedContextFieldTypes[new_field_label->type], CeedContextFieldTypes[new_field_label_i->type]); 1372 // LCOV_EXCL_STOP 1373 } else { 1374 new_field_label->type = new_field_label_i->type; 1375 } 1376 if (new_field_label->num_values != 0 && new_field_label->num_values != new_field_label_i->num_values) { 1377 // LCOV_EXCL_START 1378 CeedCall(CeedFree(&new_field_label)); 1379 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, "Incompatible field number of values on sub-operator contexts. %ld != %ld", 1380 new_field_label->num_values, new_field_label_i->num_values); 1381 // LCOV_EXCL_STOP 1382 } else { 1383 new_field_label->num_values = new_field_label_i->num_values; 1384 } 1385 } 1386 } 1387 } 1388 // -- Cleanup if field was found 1389 if (field_found) { 1390 *field_label = new_field_label; 1391 } else { 1392 // LCOV_EXCL_START 1393 CeedCall(CeedFree(&new_field_label->sub_labels)); 1394 CeedCall(CeedFree(&new_field_label)); 1395 *field_label = NULL; 1396 // LCOV_EXCL_STOP 1397 } 1398 } else { 1399 // Single, non-composite operator 1400 if (op->qf->ctx) { 1401 CeedCall(CeedQFunctionContextGetFieldLabel(op->qf->ctx, field_name, field_label)); 1402 } else { 1403 *field_label = NULL; 1404 } 1405 } 1406 1407 // Set label in operator 1408 if (*field_label) { 1409 (*field_label)->from_op = true; 1410 1411 // Move new composite label to operator 1412 if (op->num_context_labels == 0) { 1413 CeedCall(CeedCalloc(1, &op->context_labels)); 1414 op->max_context_labels = 1; 1415 } else if (op->num_context_labels == op->max_context_labels) { 1416 CeedCall(CeedRealloc(2 * op->num_context_labels, &op->context_labels)); 1417 op->max_context_labels *= 2; 1418 } 1419 op->context_labels[op->num_context_labels] = *field_label; 1420 op->num_context_labels++; 1421 } 1422 return CEED_ERROR_SUCCESS; 1423 } 1424 1425 /** 1426 @brief Set QFunctionContext field holding double precision values. 1427 1428 For composite operators, the values are set in all sub-operator QFunctionContexts that have a matching `field_name`. 1429 1430 @param[in,out] op CeedOperator 1431 @param[in] field_label Label of field to set 1432 @param[in] values Values to set 1433 1434 @return An error code: 0 - success, otherwise - failure 1435 1436 @ref User 1437 **/ 1438 int CeedOperatorSetContextDouble(CeedOperator op, CeedContextFieldLabel field_label, double *values) { 1439 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, values); 1440 } 1441 1442 /** 1443 @brief Get QFunctionContext field holding double precision values, read-only. 1444 1445 For composite operators, the values correspond to the first sub-operator QFunctionContexts that has a matching `field_name`. 1446 1447 @param[in] op CeedOperator 1448 @param[in] field_label Label of field to get 1449 @param[out] num_values Number of values in the field label 1450 @param[out] values Pointer to context values 1451 1452 @return An error code: 0 - success, otherwise - failure 1453 1454 @ref User 1455 **/ 1456 int CeedOperatorGetContextDoubleRead(CeedOperator op, CeedContextFieldLabel field_label, size_t *num_values, const double **values) { 1457 return CeedOperatorContextGetGenericRead(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, num_values, values); 1458 } 1459 1460 /** 1461 @brief Restore QFunctionContext field holding double precision values, read-only. 1462 1463 @param[in] op CeedOperator 1464 @param[in] field_label Label of field to restore 1465 @param[out] values Pointer to context values 1466 1467 @return An error code: 0 - success, otherwise - failure 1468 1469 @ref User 1470 **/ 1471 int CeedOperatorRestoreContextDoubleRead(CeedOperator op, CeedContextFieldLabel field_label, const double **values) { 1472 return CeedOperatorContextRestoreGenericRead(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, values); 1473 } 1474 1475 /** 1476 @brief Set QFunctionContext field holding int32 values. 1477 1478 For composite operators, the values are set in all sub-operator QFunctionContexts that have a matching `field_name`. 1479 1480 @param[in,out] op CeedOperator 1481 @param[in] field_label Label of field to set 1482 @param[in] values Values to set 1483 1484 @return An error code: 0 - success, otherwise - failure 1485 1486 @ref User 1487 **/ 1488 int CeedOperatorSetContextInt32(CeedOperator op, CeedContextFieldLabel field_label, int *values) { 1489 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_INT32, values); 1490 } 1491 1492 /** 1493 @brief Get QFunctionContext field holding int32 values, read-only. 1494 1495 For composite operators, the values correspond to the first sub-operator QFunctionContexts that has a matching `field_name`. 1496 1497 @param[in] op CeedOperator 1498 @param[in] field_label Label of field to get 1499 @param[out] num_values Number of int32 values in `values` 1500 @param[out] values Pointer to context values 1501 1502 @return An error code: 0 - success, otherwise - failure 1503 1504 @ref User 1505 **/ 1506 int CeedOperatorGetContextInt32Read(CeedOperator op, CeedContextFieldLabel field_label, size_t *num_values, const int **values) { 1507 return CeedOperatorContextGetGenericRead(op, field_label, CEED_CONTEXT_FIELD_INT32, num_values, values); 1508 } 1509 1510 /** 1511 @brief Restore QFunctionContext field holding int32 values, read-only. 1512 1513 @param[in] op CeedOperator 1514 @param[in] field_label Label of field to get 1515 @param[out] values Pointer to context values 1516 1517 @return An error code: 0 - success, otherwise - failure 1518 1519 @ref User 1520 **/ 1521 int CeedOperatorRestoreContextInt32Read(CeedOperator op, CeedContextFieldLabel field_label, const int **values) { 1522 return CeedOperatorContextRestoreGenericRead(op, field_label, CEED_CONTEXT_FIELD_INT32, values); 1523 } 1524 1525 /** 1526 @brief Apply CeedOperator to a vector 1527 1528 This computes the action of the operator on the specified (active) input, yielding its (active) output. 1529 All inputs and outputs must be specified using CeedOperatorSetField(). 1530 1531 Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 1532 1533 @param[in] op CeedOperator to apply 1534 @param[in] in CeedVector containing input state or @ref CEED_VECTOR_NONE if there are no active inputs 1535 @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 1536 active outputs 1537 @param[in] request Address of CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE 1538 1539 @return An error code: 0 - success, otherwise - failure 1540 1541 @ref User 1542 **/ 1543 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, CeedRequest *request) { 1544 CeedCall(CeedOperatorCheckReady(op)); 1545 1546 if (op->is_composite) { 1547 // Composite Operator 1548 if (op->ApplyComposite) { 1549 CeedCall(op->ApplyComposite(op, in, out, request)); 1550 } else { 1551 CeedInt num_suboperators; 1552 CeedOperator *sub_operators; 1553 1554 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 1555 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1556 1557 // Zero all output vectors 1558 if (out != CEED_VECTOR_NONE) CeedCall(CeedVectorSetValue(out, 0.0)); 1559 for (CeedInt i = 0; i < num_suboperators; i++) { 1560 for (CeedInt j = 0; j < sub_operators[i]->qf->num_output_fields; j++) { 1561 CeedVector vec = sub_operators[i]->output_fields[j]->vec; 1562 1563 if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) { 1564 CeedCall(CeedVectorSetValue(vec, 0.0)); 1565 } 1566 } 1567 } 1568 // Apply 1569 for (CeedInt i = 0; i < num_suboperators; i++) { 1570 CeedCall(CeedOperatorApplyAdd(sub_operators[i], in, out, request)); 1571 } 1572 } 1573 } else { 1574 // Standard Operator 1575 if (op->Apply) { 1576 CeedCall(op->Apply(op, in, out, request)); 1577 } else { 1578 // Zero all output vectors 1579 CeedQFunction qf = op->qf; 1580 1581 for (CeedInt i = 0; i < qf->num_output_fields; i++) { 1582 CeedVector vec = op->output_fields[i]->vec; 1583 1584 if (vec == CEED_VECTOR_ACTIVE) vec = out; 1585 if (vec != CEED_VECTOR_NONE) CeedCall(CeedVectorSetValue(vec, 0.0)); 1586 } 1587 // Apply 1588 if (op->num_elem) CeedCall(op->ApplyAdd(op, in, out, request)); 1589 } 1590 } 1591 return CEED_ERROR_SUCCESS; 1592 } 1593 1594 /** 1595 @brief Apply CeedOperator to a vector and add result to output vector 1596 1597 This computes the action of the operator on the specified (active) input, yielding its (active) output. 1598 All inputs and outputs must be specified using CeedOperatorSetField(). 1599 1600 @param[in] op CeedOperator to apply 1601 @param[in] in CeedVector containing input state or NULL if there are no active inputs 1602 @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 1603 @param[in] request Address of CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE 1604 1605 @return An error code: 0 - success, otherwise - failure 1606 1607 @ref User 1608 **/ 1609 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, CeedRequest *request) { 1610 CeedCall(CeedOperatorCheckReady(op)); 1611 1612 if (op->is_composite) { 1613 // Composite Operator 1614 if (op->ApplyAddComposite) { 1615 CeedCall(op->ApplyAddComposite(op, in, out, request)); 1616 } else { 1617 CeedInt num_suboperators; 1618 CeedOperator *sub_operators; 1619 1620 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 1621 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1622 for (CeedInt i = 0; i < num_suboperators; i++) { 1623 CeedCall(CeedOperatorApplyAdd(sub_operators[i], in, out, request)); 1624 } 1625 } 1626 } else if (op->num_elem) { 1627 // Standard Operator 1628 CeedCall(op->ApplyAdd(op, in, out, request)); 1629 } 1630 return CEED_ERROR_SUCCESS; 1631 } 1632 1633 /** 1634 @brief Destroy a CeedOperator 1635 1636 @param[in,out] op CeedOperator to destroy 1637 1638 @return An error code: 0 - success, otherwise - failure 1639 1640 @ref User 1641 **/ 1642 int CeedOperatorDestroy(CeedOperator *op) { 1643 if (!*op || --(*op)->ref_count > 0) { 1644 *op = NULL; 1645 return CEED_ERROR_SUCCESS; 1646 } 1647 if ((*op)->Destroy) CeedCall((*op)->Destroy(*op)); 1648 CeedCall(CeedDestroy(&(*op)->ceed)); 1649 // Free fields 1650 for (CeedInt i = 0; i < (*op)->num_fields; i++) { 1651 if ((*op)->input_fields[i]) { 1652 if ((*op)->input_fields[i]->elem_rstr != CEED_ELEMRESTRICTION_NONE) { 1653 CeedCall(CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_rstr)); 1654 } 1655 if ((*op)->input_fields[i]->basis != CEED_BASIS_NONE) { 1656 CeedCall(CeedBasisDestroy(&(*op)->input_fields[i]->basis)); 1657 } 1658 if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE && (*op)->input_fields[i]->vec != CEED_VECTOR_NONE) { 1659 CeedCall(CeedVectorDestroy(&(*op)->input_fields[i]->vec)); 1660 } 1661 CeedCall(CeedFree(&(*op)->input_fields[i]->field_name)); 1662 CeedCall(CeedFree(&(*op)->input_fields[i])); 1663 } 1664 } 1665 for (CeedInt i = 0; i < (*op)->num_fields; i++) { 1666 if ((*op)->output_fields[i]) { 1667 CeedCall(CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_rstr)); 1668 if ((*op)->output_fields[i]->basis != CEED_BASIS_NONE) { 1669 CeedCall(CeedBasisDestroy(&(*op)->output_fields[i]->basis)); 1670 } 1671 if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE && (*op)->output_fields[i]->vec != CEED_VECTOR_NONE) { 1672 CeedCall(CeedVectorDestroy(&(*op)->output_fields[i]->vec)); 1673 } 1674 CeedCall(CeedFree(&(*op)->output_fields[i]->field_name)); 1675 CeedCall(CeedFree(&(*op)->output_fields[i])); 1676 } 1677 } 1678 // Destroy sub_operators 1679 for (CeedInt i = 0; i < (*op)->num_suboperators; i++) { 1680 if ((*op)->sub_operators[i]) { 1681 CeedCall(CeedOperatorDestroy(&(*op)->sub_operators[i])); 1682 } 1683 } 1684 CeedCall(CeedQFunctionDestroy(&(*op)->qf)); 1685 CeedCall(CeedQFunctionDestroy(&(*op)->dqf)); 1686 CeedCall(CeedQFunctionDestroy(&(*op)->dqfT)); 1687 // Destroy any composite labels 1688 if ((*op)->is_composite) { 1689 for (CeedInt i = 0; i < (*op)->num_context_labels; i++) { 1690 CeedCall(CeedFree(&(*op)->context_labels[i]->sub_labels)); 1691 CeedCall(CeedFree(&(*op)->context_labels[i])); 1692 } 1693 } 1694 CeedCall(CeedFree(&(*op)->context_labels)); 1695 1696 // Destroy fallback 1697 CeedCall(CeedOperatorDestroy(&(*op)->op_fallback)); 1698 1699 // Destroy assembly data 1700 CeedCall(CeedQFunctionAssemblyDataDestroy(&(*op)->qf_assembled)); 1701 CeedCall(CeedOperatorAssemblyDataDestroy(&(*op)->op_assembled)); 1702 1703 CeedCall(CeedFree(&(*op)->input_fields)); 1704 CeedCall(CeedFree(&(*op)->output_fields)); 1705 CeedCall(CeedFree(&(*op)->sub_operators)); 1706 CeedCall(CeedFree(&(*op)->name)); 1707 CeedCall(CeedFree(op)); 1708 return CEED_ERROR_SUCCESS; 1709 } 1710 1711 /// @} 1712