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 CeedCall(CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(op, true)); 313 return CEED_ERROR_SUCCESS; 314 } 315 316 /** 317 @brief Get QFunctionContext field values of the specified type, read-only. 318 319 For composite operators, the values retrieved are for the first sub-operator QFunctionContext that have a matching `field_name`. 320 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 321 any field of a matching type. 322 323 @param[in,out] op CeedOperator 324 @param[in] field_label Label of field to set 325 @param[in] field_type Type of field to set 326 @param[out] num_values Number of values of type `field_type` in array `values` 327 @param[out] values Values in the label 328 329 @return An error code: 0 - success, otherwise - failure 330 331 @ref User 332 **/ 333 static int CeedOperatorContextGetGenericRead(CeedOperator op, CeedContextFieldLabel field_label, CeedContextFieldType field_type, size_t *num_values, 334 void *values) { 335 bool is_composite = false; 336 337 CeedCheck(field_label, op->ceed, CEED_ERROR_UNSUPPORTED, "Invalid field label"); 338 339 *(void **)values = NULL; 340 *num_values = 0; 341 342 // Check if field_label and op correspond 343 if (field_label->from_op) { 344 CeedInt index = -1; 345 346 for (CeedInt i = 0; i < op->num_context_labels; i++) { 347 if (op->context_labels[i] == field_label) index = i; 348 } 349 CeedCheck(index != -1, op->ceed, CEED_ERROR_UNSUPPORTED, "ContextFieldLabel does not correspond to the operator"); 350 } 351 352 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 353 if (is_composite) { 354 CeedInt num_sub; 355 CeedOperator *sub_operators; 356 357 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_sub)); 358 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 359 CeedCheck(num_sub == field_label->num_sub_labels, op->ceed, CEED_ERROR_UNSUPPORTED, 360 "Composite operator modified after ContextFieldLabel created"); 361 362 for (CeedInt i = 0; i < num_sub; i++) { 363 // Try every sub-operator, ok if some sub-operators do not have field 364 if (field_label->sub_labels[i] && sub_operators[i]->qf->ctx) { 365 CeedCall(CeedQFunctionContextGetGenericRead(sub_operators[i]->qf->ctx, field_label->sub_labels[i], field_type, num_values, values)); 366 return CEED_ERROR_SUCCESS; 367 } 368 } 369 } else { 370 CeedCheck(op->qf->ctx, op->ceed, CEED_ERROR_UNSUPPORTED, "QFunction does not have context data"); 371 CeedCall(CeedQFunctionContextGetGenericRead(op->qf->ctx, field_label, field_type, num_values, values)); 372 } 373 return CEED_ERROR_SUCCESS; 374 } 375 376 /** 377 @brief Restore QFunctionContext field values of the specified type, read-only. 378 379 For composite operators, the values restored are for the first sub-operator QFunctionContext that have a matching `field_name`. 380 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 381 any field of a matching type. 382 383 @param[in,out] op CeedOperator 384 @param[in] field_label Label of field to set 385 @param[in] field_type Type of field to set 386 @param[in] values Values array to restore 387 388 @return An error code: 0 - success, otherwise - failure 389 390 @ref User 391 **/ 392 static int CeedOperatorContextRestoreGenericRead(CeedOperator op, CeedContextFieldLabel field_label, CeedContextFieldType field_type, void *values) { 393 bool is_composite = false; 394 395 CeedCheck(field_label, op->ceed, CEED_ERROR_UNSUPPORTED, "Invalid field label"); 396 397 // Check if field_label and op correspond 398 if (field_label->from_op) { 399 CeedInt index = -1; 400 401 for (CeedInt i = 0; i < op->num_context_labels; i++) { 402 if (op->context_labels[i] == field_label) index = i; 403 } 404 CeedCheck(index != -1, op->ceed, CEED_ERROR_UNSUPPORTED, "ContextFieldLabel does not correspond to the operator"); 405 } 406 407 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 408 if (is_composite) { 409 CeedInt num_sub; 410 CeedOperator *sub_operators; 411 412 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_sub)); 413 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 414 CeedCheck(num_sub == field_label->num_sub_labels, op->ceed, CEED_ERROR_UNSUPPORTED, 415 "Composite operator modified after ContextFieldLabel created"); 416 417 for (CeedInt i = 0; i < num_sub; i++) { 418 // Try every sub-operator, ok if some sub-operators do not have field 419 if (field_label->sub_labels[i] && sub_operators[i]->qf->ctx) { 420 CeedCall(CeedQFunctionContextRestoreGenericRead(sub_operators[i]->qf->ctx, field_label->sub_labels[i], field_type, values)); 421 return CEED_ERROR_SUCCESS; 422 } 423 } 424 } else { 425 CeedCheck(op->qf->ctx, op->ceed, CEED_ERROR_UNSUPPORTED, "QFunction does not have context data"); 426 CeedCall(CeedQFunctionContextRestoreGenericRead(op->qf->ctx, field_label, field_type, values)); 427 } 428 return CEED_ERROR_SUCCESS; 429 } 430 431 /// @} 432 433 /// ---------------------------------------------------------------------------- 434 /// CeedOperator Backend API 435 /// ---------------------------------------------------------------------------- 436 /// @addtogroup CeedOperatorBackend 437 /// @{ 438 439 /** 440 @brief Get the number of arguments associated with a CeedOperator 441 442 @param[in] op CeedOperator 443 @param[out] num_args Variable to store vector number of arguments 444 445 @return An error code: 0 - success, otherwise - failure 446 447 @ref Backend 448 **/ 449 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *num_args) { 450 CeedCheck(!op->is_composite, op->ceed, CEED_ERROR_MINOR, "Not defined for composite operators"); 451 *num_args = op->num_fields; 452 return CEED_ERROR_SUCCESS; 453 } 454 455 /** 456 @brief Get the setup status of a CeedOperator 457 458 @param[in] op CeedOperator 459 @param[out] is_setup_done Variable to store setup status 460 461 @return An error code: 0 - success, otherwise - failure 462 463 @ref Backend 464 **/ 465 int CeedOperatorIsSetupDone(CeedOperator op, bool *is_setup_done) { 466 *is_setup_done = op->is_backend_setup; 467 return CEED_ERROR_SUCCESS; 468 } 469 470 /** 471 @brief Get the QFunction associated with a CeedOperator 472 473 @param[in] op CeedOperator 474 @param[out] qf Variable to store QFunction 475 476 @return An error code: 0 - success, otherwise - failure 477 478 @ref Backend 479 **/ 480 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) { 481 CeedCheck(!op->is_composite, op->ceed, CEED_ERROR_MINOR, "Not defined for composite operator"); 482 *qf = op->qf; 483 return CEED_ERROR_SUCCESS; 484 } 485 486 /** 487 @brief Get a boolean value indicating if the CeedOperator is composite 488 489 @param[in] op CeedOperator 490 @param[out] is_composite Variable to store composite status 491 492 @return An error code: 0 - success, otherwise - failure 493 494 @ref Backend 495 **/ 496 int CeedOperatorIsComposite(CeedOperator op, bool *is_composite) { 497 *is_composite = op->is_composite; 498 return CEED_ERROR_SUCCESS; 499 } 500 501 /** 502 @brief Get the backend data of a CeedOperator 503 504 @param[in] op CeedOperator 505 @param[out] data Variable to store data 506 507 @return An error code: 0 - success, otherwise - failure 508 509 @ref Backend 510 **/ 511 int CeedOperatorGetData(CeedOperator op, void *data) { 512 *(void **)data = op->data; 513 return CEED_ERROR_SUCCESS; 514 } 515 516 /** 517 @brief Set the backend data of a CeedOperator 518 519 @param[in,out] op CeedOperator 520 @param[in] data Data to set 521 522 @return An error code: 0 - success, otherwise - failure 523 524 @ref Backend 525 **/ 526 int CeedOperatorSetData(CeedOperator op, void *data) { 527 op->data = data; 528 return CEED_ERROR_SUCCESS; 529 } 530 531 /** 532 @brief Increment the reference counter for a CeedOperator 533 534 @param[in,out] op CeedOperator to increment the reference counter 535 536 @return An error code: 0 - success, otherwise - failure 537 538 @ref Backend 539 **/ 540 int CeedOperatorReference(CeedOperator op) { 541 op->ref_count++; 542 return CEED_ERROR_SUCCESS; 543 } 544 545 /** 546 @brief Set the setup flag of a CeedOperator to True 547 548 @param[in,out] op CeedOperator 549 550 @return An error code: 0 - success, otherwise - failure 551 552 @ref Backend 553 **/ 554 int CeedOperatorSetSetupDone(CeedOperator op) { 555 op->is_backend_setup = true; 556 return CEED_ERROR_SUCCESS; 557 } 558 559 /// @} 560 561 /// ---------------------------------------------------------------------------- 562 /// CeedOperator Public API 563 /// ---------------------------------------------------------------------------- 564 /// @addtogroup CeedOperatorUser 565 /// @{ 566 567 /** 568 @brief Create a CeedOperator and associate a CeedQFunction. 569 570 A CeedBasis and CeedElemRestriction can be associated with CeedQFunction fields with \ref CeedOperatorSetField. 571 572 @param[in] ceed Ceed object where the CeedOperator will be created 573 @param[in] qf QFunction defining the action of the operator at quadrature points 574 @param[in] dqf QFunction defining the action of the Jacobian of @a qf (or @ref CEED_QFUNCTION_NONE) 575 @param[in] dqfT QFunction defining the action of the transpose of the Jacobian of @a qf (or @ref CEED_QFUNCTION_NONE) 576 @param[out] op Address of the variable where the newly created CeedOperator will be stored 577 578 @return An error code: 0 - success, otherwise - failure 579 580 @ref User 581 */ 582 int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, CeedQFunction dqfT, CeedOperator *op) { 583 if (!ceed->OperatorCreate) { 584 Ceed delegate; 585 586 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Operator")); 587 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support OperatorCreate"); 588 CeedCall(CeedOperatorCreate(delegate, qf, dqf, dqfT, op)); 589 return CEED_ERROR_SUCCESS; 590 } 591 592 CeedCheck(qf && qf != CEED_QFUNCTION_NONE, ceed, CEED_ERROR_MINOR, "Operator must have a valid QFunction."); 593 594 CeedCall(CeedCalloc(1, op)); 595 CeedCall(CeedReferenceCopy(ceed, &(*op)->ceed)); 596 (*op)->ref_count = 1; 597 (*op)->input_size = -1; 598 (*op)->output_size = -1; 599 CeedCall(CeedQFunctionReferenceCopy(qf, &(*op)->qf)); 600 if (dqf && dqf != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionReferenceCopy(dqf, &(*op)->dqf)); 601 if (dqfT && dqfT != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionReferenceCopy(dqfT, &(*op)->dqfT)); 602 CeedCall(CeedQFunctionAssemblyDataCreate(ceed, &(*op)->qf_assembled)); 603 CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*op)->input_fields)); 604 CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*op)->output_fields)); 605 CeedCall(ceed->OperatorCreate(*op)); 606 return CEED_ERROR_SUCCESS; 607 } 608 609 /** 610 @brief Create an operator that composes the action of several operators 611 612 @param[in] ceed Ceed object where the CeedOperator will be created 613 @param[out] op Address of the variable where the newly created Composite CeedOperator will be stored 614 615 @return An error code: 0 - success, otherwise - failure 616 617 @ref User 618 */ 619 int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) { 620 if (!ceed->CompositeOperatorCreate) { 621 Ceed delegate; 622 623 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Operator")); 624 if (delegate) { 625 CeedCall(CeedCompositeOperatorCreate(delegate, op)); 626 return CEED_ERROR_SUCCESS; 627 } 628 } 629 630 CeedCall(CeedCalloc(1, op)); 631 CeedCall(CeedReferenceCopy(ceed, &(*op)->ceed)); 632 (*op)->ref_count = 1; 633 (*op)->is_composite = true; 634 CeedCall(CeedCalloc(CEED_COMPOSITE_MAX, &(*op)->sub_operators)); 635 (*op)->input_size = -1; 636 (*op)->output_size = -1; 637 638 if (ceed->CompositeOperatorCreate) CeedCall(ceed->CompositeOperatorCreate(*op)); 639 return CEED_ERROR_SUCCESS; 640 } 641 642 /** 643 @brief Copy the pointer to a CeedOperator. 644 645 Both pointers should be destroyed with `CeedOperatorDestroy()`. 646 647 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. 648 This CeedOperator will be destroyed if `op_copy` is the only reference to this CeedOperator. 649 650 @param[in] op CeedOperator to copy reference to 651 @param[in,out] op_copy Variable to store copied reference 652 653 @return An error code: 0 - success, otherwise - failure 654 655 @ref User 656 **/ 657 int CeedOperatorReferenceCopy(CeedOperator op, CeedOperator *op_copy) { 658 CeedCall(CeedOperatorReference(op)); 659 CeedCall(CeedOperatorDestroy(op_copy)); 660 *op_copy = op; 661 return CEED_ERROR_SUCCESS; 662 } 663 664 /** 665 @brief Provide a field to a CeedOperator for use by its CeedQFunction. 666 667 This function is used to specify both active and passive fields to a CeedOperator. 668 For passive fields, a vector @arg v must be provided. 669 Passive fields can inputs or outputs (updated in-place when operator is applied). 670 671 Active fields must be specified using this function, but their data (in a CeedVector) is passed in CeedOperatorApply(). 672 There can be at most one active input CeedVector and at most one active output CeedVector passed to CeedOperatorApply(). 673 674 The number of quadrature points must agree across all points. 675 When using @ref CEED_BASIS_NONE, the number of quadrature points is determined by the element size of r. 676 677 @param[in,out] op CeedOperator on which to provide the field 678 @param[in] field_name Name of the field (to be matched with the name used by CeedQFunction) 679 @param[in] r CeedElemRestriction 680 @param[in] b CeedBasis in which the field resides or @ref CEED_BASIS_NONE if collocated with quadrature points 681 @param[in] v CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE if field is active or @ref CEED_VECTOR_NONE 682 if using @ref CEED_EVAL_WEIGHT in the QFunction 683 684 @return An error code: 0 - success, otherwise - failure 685 686 @ref User 687 **/ 688 int CeedOperatorSetField(CeedOperator op, const char *field_name, CeedElemRestriction r, CeedBasis b, CeedVector v) { 689 bool is_input = true; 690 CeedInt num_elem = 0, num_qpts = 0; 691 CeedQFunctionField qf_field; 692 CeedOperatorField *op_field; 693 694 CeedCheck(!op->is_composite, op->ceed, CEED_ERROR_INCOMPATIBLE, "Cannot add field to composite operator."); 695 CeedCheck(!op->is_immutable, op->ceed, CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable"); 696 CeedCheck(r, op->ceed, CEED_ERROR_INCOMPATIBLE, "ElemRestriction r for field \"%s\" must be non-NULL.", field_name); 697 CeedCheck(b, op->ceed, CEED_ERROR_INCOMPATIBLE, "Basis b for field \"%s\" must be non-NULL.", field_name); 698 CeedCheck(v, op->ceed, CEED_ERROR_INCOMPATIBLE, "Vector v for field \"%s\" must be non-NULL.", field_name); 699 700 CeedCall(CeedElemRestrictionGetNumElements(r, &num_elem)); 701 CeedCheck(r == CEED_ELEMRESTRICTION_NONE || !op->has_restriction || op->num_elem == num_elem, op->ceed, CEED_ERROR_DIMENSION, 702 "ElemRestriction with %" CeedInt_FMT " elements incompatible with prior %" CeedInt_FMT " elements", num_elem, op->num_elem); 703 { 704 CeedRestrictionType rstr_type; 705 706 CeedCall(CeedElemRestrictionGetType(r, &rstr_type)); 707 CeedCheck(rstr_type != CEED_RESTRICTION_POINTS, op->ceed, CEED_ERROR_UNSUPPORTED, 708 "CeedElemRestrictionAtPoints not supported for standard operator fields"); 709 } 710 711 if (b == CEED_BASIS_NONE) CeedCall(CeedElemRestrictionGetElementSize(r, &num_qpts)); 712 else CeedCall(CeedBasisGetNumQuadraturePoints(b, &num_qpts)); 713 CeedCheck(op->num_qpts == 0 || op->num_qpts == num_qpts, op->ceed, CEED_ERROR_DIMENSION, 714 "%s must correspond to the same number of quadrature points as previously added Bases. Found %" CeedInt_FMT 715 " quadrature points but expected %" CeedInt_FMT " quadrature points.", 716 b == CEED_BASIS_NONE ? "ElemRestriction" : "Basis", num_qpts, op->num_qpts); 717 for (CeedInt i = 0; i < op->qf->num_input_fields; i++) { 718 if (!strcmp(field_name, (*op->qf->input_fields[i]).field_name)) { 719 qf_field = op->qf->input_fields[i]; 720 op_field = &op->input_fields[i]; 721 goto found; 722 } 723 } 724 is_input = false; 725 for (CeedInt i = 0; i < op->qf->num_output_fields; i++) { 726 if (!strcmp(field_name, (*op->qf->output_fields[i]).field_name)) { 727 qf_field = op->qf->output_fields[i]; 728 op_field = &op->output_fields[i]; 729 goto found; 730 } 731 } 732 // LCOV_EXCL_START 733 return CeedError(op->ceed, CEED_ERROR_INCOMPLETE, "QFunction has no knowledge of field '%s'", field_name); 734 // LCOV_EXCL_STOP 735 found: 736 CeedCall(CeedOperatorCheckField(op->ceed, qf_field, r, b)); 737 CeedCall(CeedCalloc(1, op_field)); 738 739 if (v == CEED_VECTOR_ACTIVE) { 740 CeedSize l_size; 741 742 CeedCall(CeedElemRestrictionGetLVectorSize(r, &l_size)); 743 if (is_input) { 744 if (op->input_size == -1) op->input_size = l_size; 745 CeedCheck(l_size == op->input_size, op->ceed, CEED_ERROR_INCOMPATIBLE, "LVector size %td does not match previous size %td", l_size, 746 op->input_size); 747 } else { 748 if (op->output_size == -1) op->output_size = l_size; 749 CeedCheck(l_size == op->output_size, op->ceed, CEED_ERROR_INCOMPATIBLE, "LVector size %td does not match previous size %td", l_size, 750 op->output_size); 751 } 752 } 753 754 CeedCall(CeedVectorReferenceCopy(v, &(*op_field)->vec)); 755 CeedCall(CeedElemRestrictionReferenceCopy(r, &(*op_field)->elem_rstr)); 756 if (r != CEED_ELEMRESTRICTION_NONE && !op->has_restriction) { 757 op->num_elem = num_elem; 758 op->has_restriction = true; // Restriction set, but num_elem may be 0 759 } 760 CeedCall(CeedBasisReferenceCopy(b, &(*op_field)->basis)); 761 if (op->num_qpts == 0) op->num_qpts = num_qpts; 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 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 Set QFunctionContext field holding boolean values. 1501 1502 For composite operators, the values are set in all sub-operator QFunctionContexts that have a matching `field_name`. 1503 1504 @param[in,out] op CeedOperator 1505 @param[in] field_label Label of field to set 1506 @param[in] values Values to set 1507 1508 @return An error code: 0 - success, otherwise - failure 1509 1510 @ref User 1511 **/ 1512 int CeedOperatorSetContextBoolean(CeedOperator op, CeedContextFieldLabel field_label, bool *values) { 1513 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_BOOL, values); 1514 } 1515 1516 /** 1517 @brief Get QFunctionContext field holding boolean values, read-only. 1518 1519 For composite operators, the values correspond to the first sub-operator QFunctionContexts that has a matching `field_name`. 1520 1521 @param[in] op CeedOperator 1522 @param[in] field_label Label of field to get 1523 @param[out] num_values Number of int32 values in `values` 1524 @param[out] values Pointer to context values 1525 1526 @return An error code: 0 - success, otherwise - failure 1527 1528 @ref User 1529 **/ 1530 int CeedOperatorGetContextBooleanRead(CeedOperator op, CeedContextFieldLabel field_label, size_t *num_values, const bool **values) { 1531 return CeedOperatorContextGetGenericRead(op, field_label, CEED_CONTEXT_FIELD_BOOL, num_values, values); 1532 } 1533 1534 /** 1535 @brief Restore QFunctionContext field holding boolean values, read-only. 1536 1537 @param[in] op CeedOperator 1538 @param[in] field_label Label of field to get 1539 @param[out] values Pointer to context values 1540 1541 @return An error code: 0 - success, otherwise - failure 1542 1543 @ref User 1544 **/ 1545 int CeedOperatorRestoreContextBooleanRead(CeedOperator op, CeedContextFieldLabel field_label, const bool **values) { 1546 return CeedOperatorContextRestoreGenericRead(op, field_label, CEED_CONTEXT_FIELD_BOOL, values); 1547 } 1548 1549 /** 1550 @brief Apply CeedOperator to a vector 1551 1552 This computes the action of the operator on the specified (active) input, yielding its (active) output. 1553 All inputs and outputs must be specified using CeedOperatorSetField(). 1554 1555 Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 1556 1557 @param[in] op CeedOperator to apply 1558 @param[in] in CeedVector containing input state or @ref CEED_VECTOR_NONE if there are no active inputs 1559 @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 1560 active outputs 1561 @param[in] request Address of CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE 1562 1563 @return An error code: 0 - success, otherwise - failure 1564 1565 @ref User 1566 **/ 1567 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, CeedRequest *request) { 1568 CeedCall(CeedOperatorCheckReady(op)); 1569 1570 if (op->is_composite) { 1571 // Composite Operator 1572 if (op->ApplyComposite) { 1573 CeedCall(op->ApplyComposite(op, in, out, request)); 1574 } else { 1575 CeedInt num_suboperators; 1576 CeedOperator *sub_operators; 1577 1578 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 1579 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1580 1581 // Zero all output vectors 1582 if (out != CEED_VECTOR_NONE) CeedCall(CeedVectorSetValue(out, 0.0)); 1583 for (CeedInt i = 0; i < num_suboperators; i++) { 1584 for (CeedInt j = 0; j < sub_operators[i]->qf->num_output_fields; j++) { 1585 CeedVector vec = sub_operators[i]->output_fields[j]->vec; 1586 1587 if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) { 1588 CeedCall(CeedVectorSetValue(vec, 0.0)); 1589 } 1590 } 1591 } 1592 // Apply 1593 for (CeedInt i = 0; i < num_suboperators; i++) { 1594 CeedCall(CeedOperatorApplyAdd(sub_operators[i], in, out, request)); 1595 } 1596 } 1597 } else { 1598 // Standard Operator 1599 if (op->Apply) { 1600 CeedCall(op->Apply(op, in, out, request)); 1601 } else { 1602 // Zero all output vectors 1603 CeedQFunction qf = op->qf; 1604 1605 for (CeedInt i = 0; i < qf->num_output_fields; i++) { 1606 CeedVector vec = op->output_fields[i]->vec; 1607 1608 if (vec == CEED_VECTOR_ACTIVE) vec = out; 1609 if (vec != CEED_VECTOR_NONE) CeedCall(CeedVectorSetValue(vec, 0.0)); 1610 } 1611 // Apply 1612 if (op->num_elem) CeedCall(op->ApplyAdd(op, in, out, request)); 1613 } 1614 } 1615 return CEED_ERROR_SUCCESS; 1616 } 1617 1618 /** 1619 @brief Apply CeedOperator to a vector and add result to output vector 1620 1621 This computes the action of the operator on the specified (active) input, yielding its (active) output. 1622 All inputs and outputs must be specified using CeedOperatorSetField(). 1623 1624 @param[in] op CeedOperator to apply 1625 @param[in] in CeedVector containing input state or NULL if there are no active inputs 1626 @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 1627 @param[in] request Address of CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE 1628 1629 @return An error code: 0 - success, otherwise - failure 1630 1631 @ref User 1632 **/ 1633 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, CeedRequest *request) { 1634 CeedCall(CeedOperatorCheckReady(op)); 1635 1636 if (op->is_composite) { 1637 // Composite Operator 1638 if (op->ApplyAddComposite) { 1639 CeedCall(op->ApplyAddComposite(op, in, out, request)); 1640 } else { 1641 CeedInt num_suboperators; 1642 CeedOperator *sub_operators; 1643 1644 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 1645 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1646 for (CeedInt i = 0; i < num_suboperators; i++) { 1647 CeedCall(CeedOperatorApplyAdd(sub_operators[i], in, out, request)); 1648 } 1649 } 1650 } else if (op->num_elem) { 1651 // Standard Operator 1652 CeedCall(op->ApplyAdd(op, in, out, request)); 1653 } 1654 return CEED_ERROR_SUCCESS; 1655 } 1656 1657 /** 1658 @brief Destroy a CeedOperator 1659 1660 @param[in,out] op CeedOperator to destroy 1661 1662 @return An error code: 0 - success, otherwise - failure 1663 1664 @ref User 1665 **/ 1666 int CeedOperatorDestroy(CeedOperator *op) { 1667 if (!*op || --(*op)->ref_count > 0) { 1668 *op = NULL; 1669 return CEED_ERROR_SUCCESS; 1670 } 1671 if ((*op)->Destroy) CeedCall((*op)->Destroy(*op)); 1672 CeedCall(CeedDestroy(&(*op)->ceed)); 1673 // Free fields 1674 for (CeedInt i = 0; i < (*op)->num_fields; i++) { 1675 if ((*op)->input_fields[i]) { 1676 if ((*op)->input_fields[i]->elem_rstr != CEED_ELEMRESTRICTION_NONE) { 1677 CeedCall(CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_rstr)); 1678 } 1679 if ((*op)->input_fields[i]->basis != CEED_BASIS_NONE) { 1680 CeedCall(CeedBasisDestroy(&(*op)->input_fields[i]->basis)); 1681 } 1682 if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE && (*op)->input_fields[i]->vec != CEED_VECTOR_NONE) { 1683 CeedCall(CeedVectorDestroy(&(*op)->input_fields[i]->vec)); 1684 } 1685 CeedCall(CeedFree(&(*op)->input_fields[i]->field_name)); 1686 CeedCall(CeedFree(&(*op)->input_fields[i])); 1687 } 1688 } 1689 for (CeedInt i = 0; i < (*op)->num_fields; i++) { 1690 if ((*op)->output_fields[i]) { 1691 CeedCall(CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_rstr)); 1692 if ((*op)->output_fields[i]->basis != CEED_BASIS_NONE) { 1693 CeedCall(CeedBasisDestroy(&(*op)->output_fields[i]->basis)); 1694 } 1695 if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE && (*op)->output_fields[i]->vec != CEED_VECTOR_NONE) { 1696 CeedCall(CeedVectorDestroy(&(*op)->output_fields[i]->vec)); 1697 } 1698 CeedCall(CeedFree(&(*op)->output_fields[i]->field_name)); 1699 CeedCall(CeedFree(&(*op)->output_fields[i])); 1700 } 1701 } 1702 // Destroy sub_operators 1703 for (CeedInt i = 0; i < (*op)->num_suboperators; i++) { 1704 if ((*op)->sub_operators[i]) { 1705 CeedCall(CeedOperatorDestroy(&(*op)->sub_operators[i])); 1706 } 1707 } 1708 CeedCall(CeedQFunctionDestroy(&(*op)->qf)); 1709 CeedCall(CeedQFunctionDestroy(&(*op)->dqf)); 1710 CeedCall(CeedQFunctionDestroy(&(*op)->dqfT)); 1711 // Destroy any composite labels 1712 if ((*op)->is_composite) { 1713 for (CeedInt i = 0; i < (*op)->num_context_labels; i++) { 1714 CeedCall(CeedFree(&(*op)->context_labels[i]->sub_labels)); 1715 CeedCall(CeedFree(&(*op)->context_labels[i])); 1716 } 1717 } 1718 CeedCall(CeedFree(&(*op)->context_labels)); 1719 1720 // Destroy fallback 1721 CeedCall(CeedOperatorDestroy(&(*op)->op_fallback)); 1722 1723 // Destroy assembly data 1724 CeedCall(CeedQFunctionAssemblyDataDestroy(&(*op)->qf_assembled)); 1725 CeedCall(CeedOperatorAssemblyDataDestroy(&(*op)->op_assembled)); 1726 1727 CeedCall(CeedFree(&(*op)->input_fields)); 1728 CeedCall(CeedFree(&(*op)->output_fields)); 1729 CeedCall(CeedFree(&(*op)->sub_operators)); 1730 CeedCall(CeedFree(&(*op)->name)); 1731 CeedCall(CeedFree(op)); 1732 return CEED_ERROR_SUCCESS; 1733 } 1734 1735 /// @} 1736