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 a CeedOperator for evaluation at evaluation at arbitrary points in each element. 611 612 A CeedBasis and CeedElemRestriction can be associated with CeedQFunction fields with \ref CeedOperatorSetField. 613 The locations of each point are set with \ref CeedOperatorAtPointsSetPoints. 614 615 @param[in] ceed Ceed object where the CeedOperator will be created 616 @param[in] qf QFunction defining the action of the operator at quadrature points 617 @param[in] dqf QFunction defining the action of the Jacobian of @a qf (or @ref CEED_QFUNCTION_NONE) 618 @param[in] dqfT QFunction defining the action of the transpose of the Jacobian of @a qf (or @ref CEED_QFUNCTION_NONE) 619 @param[out] op Address of the variable where the newly created CeedOperator will be stored 620 621 @return An error code: 0 - success, otherwise - failure 622 623 @ref User 624 */ 625 int CeedOperatorCreateAtPoints(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, CeedQFunction dqfT, CeedOperator *op) { 626 if (!ceed->OperatorCreateAtPoints) { 627 Ceed delegate; 628 629 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Operator")); 630 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support OperatorCreateAtPoints"); 631 CeedCall(CeedOperatorCreateAtPoints(delegate, qf, dqf, dqfT, op)); 632 return CEED_ERROR_SUCCESS; 633 } 634 635 CeedCheck(qf && qf != CEED_QFUNCTION_NONE, ceed, CEED_ERROR_MINOR, "Operator must have a valid QFunction."); 636 637 CeedCall(CeedCalloc(1, op)); 638 CeedCall(CeedReferenceCopy(ceed, &(*op)->ceed)); 639 (*op)->ref_count = 1; 640 (*op)->is_at_points = true; 641 (*op)->input_size = -1; 642 (*op)->output_size = -1; 643 CeedCall(CeedQFunctionReferenceCopy(qf, &(*op)->qf)); 644 if (dqf && dqf != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionReferenceCopy(dqf, &(*op)->dqf)); 645 if (dqfT && dqfT != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionReferenceCopy(dqfT, &(*op)->dqfT)); 646 CeedCall(CeedQFunctionAssemblyDataCreate(ceed, &(*op)->qf_assembled)); 647 CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*op)->input_fields)); 648 CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*op)->output_fields)); 649 CeedCall(ceed->OperatorCreateAtPoints(*op)); 650 return CEED_ERROR_SUCCESS; 651 } 652 653 /** 654 @brief Create an operator that composes the action of several operators 655 656 @param[in] ceed Ceed object where the CeedOperator will be created 657 @param[out] op Address of the variable where the newly created Composite CeedOperator will be stored 658 659 @return An error code: 0 - success, otherwise - failure 660 661 @ref User 662 */ 663 int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) { 664 if (!ceed->CompositeOperatorCreate) { 665 Ceed delegate; 666 667 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Operator")); 668 if (delegate) { 669 CeedCall(CeedCompositeOperatorCreate(delegate, op)); 670 return CEED_ERROR_SUCCESS; 671 } 672 } 673 674 CeedCall(CeedCalloc(1, op)); 675 CeedCall(CeedReferenceCopy(ceed, &(*op)->ceed)); 676 (*op)->ref_count = 1; 677 (*op)->is_composite = true; 678 CeedCall(CeedCalloc(CEED_COMPOSITE_MAX, &(*op)->sub_operators)); 679 (*op)->input_size = -1; 680 (*op)->output_size = -1; 681 682 if (ceed->CompositeOperatorCreate) CeedCall(ceed->CompositeOperatorCreate(*op)); 683 return CEED_ERROR_SUCCESS; 684 } 685 686 /** 687 @brief Copy the pointer to a CeedOperator. 688 689 Both pointers should be destroyed with `CeedOperatorDestroy()`. 690 691 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. 692 This CeedOperator will be destroyed if `op_copy` is the only reference to this CeedOperator. 693 694 @param[in] op CeedOperator to copy reference to 695 @param[in,out] op_copy Variable to store copied reference 696 697 @return An error code: 0 - success, otherwise - failure 698 699 @ref User 700 **/ 701 int CeedOperatorReferenceCopy(CeedOperator op, CeedOperator *op_copy) { 702 CeedCall(CeedOperatorReference(op)); 703 CeedCall(CeedOperatorDestroy(op_copy)); 704 *op_copy = op; 705 return CEED_ERROR_SUCCESS; 706 } 707 708 /** 709 @brief Provide a field to a CeedOperator for use by its CeedQFunction. 710 711 This function is used to specify both active and passive fields to a CeedOperator. 712 For passive fields, a vector @arg v must be provided. 713 Passive fields can inputs or outputs (updated in-place when operator is applied). 714 715 Active fields must be specified using this function, but their data (in a CeedVector) is passed in CeedOperatorApply(). 716 There can be at most one active input CeedVector and at most one active output CeedVector passed to CeedOperatorApply(). 717 718 The number of quadrature points must agree across all points. 719 When using @ref CEED_BASIS_NONE, the number of quadrature points is determined by the element size of r. 720 721 @param[in,out] op CeedOperator on which to provide the field 722 @param[in] field_name Name of the field (to be matched with the name used by CeedQFunction) 723 @param[in] r CeedElemRestriction 724 @param[in] b CeedBasis in which the field resides or @ref CEED_BASIS_NONE if collocated with quadrature points 725 @param[in] v CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE if field is active or @ref CEED_VECTOR_NONE 726 if using @ref CEED_EVAL_WEIGHT in the QFunction 727 728 @return An error code: 0 - success, otherwise - failure 729 730 @ref User 731 **/ 732 int CeedOperatorSetField(CeedOperator op, const char *field_name, CeedElemRestriction r, CeedBasis b, CeedVector v) { 733 bool is_input = true; 734 CeedInt num_elem = 0, num_qpts = 0; 735 CeedQFunctionField qf_field; 736 CeedOperatorField *op_field; 737 738 CeedCheck(!op->is_composite, op->ceed, CEED_ERROR_INCOMPATIBLE, "Cannot add field to composite operator."); 739 CeedCheck(!op->is_immutable, op->ceed, CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable"); 740 CeedCheck(r, op->ceed, CEED_ERROR_INCOMPATIBLE, "ElemRestriction r for field \"%s\" must be non-NULL.", field_name); 741 CeedCheck(b, op->ceed, CEED_ERROR_INCOMPATIBLE, "Basis b for field \"%s\" must be non-NULL.", field_name); 742 CeedCheck(v, op->ceed, CEED_ERROR_INCOMPATIBLE, "Vector v for field \"%s\" must be non-NULL.", field_name); 743 744 CeedCall(CeedElemRestrictionGetNumElements(r, &num_elem)); 745 CeedCheck(r == CEED_ELEMRESTRICTION_NONE || !op->has_restriction || op->num_elem == num_elem, op->ceed, CEED_ERROR_DIMENSION, 746 "ElemRestriction with %" CeedInt_FMT " elements incompatible with prior %" CeedInt_FMT " elements", num_elem, op->num_elem); 747 { 748 CeedRestrictionType rstr_type; 749 750 CeedCall(CeedElemRestrictionGetType(r, &rstr_type)); 751 if (rstr_type == CEED_RESTRICTION_POINTS) { 752 CeedCheck(op->is_at_points, op->ceed, CEED_ERROR_UNSUPPORTED, "ElemRestrictionAtPoints not supported for standard operator fields"); 753 CeedCheck(b == CEED_BASIS_NONE, op->ceed, CEED_ERROR_UNSUPPORTED, "ElemRestrictionAtPoints must be used with CEED_BASIS_NONE"); 754 if (!op->first_points_rstr) { 755 CeedCall(CeedElemRestrictionReferenceCopy(r, &op->first_points_rstr)); 756 } else { 757 bool are_compatible; 758 759 CeedCall(CeedElemRestrictionAtPointsAreCompatible(op->first_points_rstr, r, &are_compatible)); 760 CeedCheck(are_compatible, op->ceed, CEED_ERROR_INCOMPATIBLE, 761 "ElemRestriction must have compatible offsets with previously set ElemRestriction"); 762 } 763 } 764 } 765 766 if (b == CEED_BASIS_NONE) CeedCall(CeedElemRestrictionGetElementSize(r, &num_qpts)); 767 else CeedCall(CeedBasisGetNumQuadraturePoints(b, &num_qpts)); 768 CeedCheck(op->num_qpts == 0 || op->num_qpts == num_qpts, op->ceed, CEED_ERROR_DIMENSION, 769 "%s must correspond to the same number of quadrature points as previously added Bases. Found %" CeedInt_FMT 770 " quadrature points but expected %" CeedInt_FMT " quadrature points.", 771 b == CEED_BASIS_NONE ? "ElemRestriction" : "Basis", num_qpts, op->num_qpts); 772 for (CeedInt i = 0; i < op->qf->num_input_fields; i++) { 773 if (!strcmp(field_name, (*op->qf->input_fields[i]).field_name)) { 774 qf_field = op->qf->input_fields[i]; 775 op_field = &op->input_fields[i]; 776 goto found; 777 } 778 } 779 is_input = false; 780 for (CeedInt i = 0; i < op->qf->num_output_fields; i++) { 781 if (!strcmp(field_name, (*op->qf->output_fields[i]).field_name)) { 782 qf_field = op->qf->output_fields[i]; 783 op_field = &op->output_fields[i]; 784 goto found; 785 } 786 } 787 // LCOV_EXCL_START 788 return CeedError(op->ceed, CEED_ERROR_INCOMPLETE, "QFunction has no knowledge of field '%s'", field_name); 789 // LCOV_EXCL_STOP 790 found: 791 CeedCall(CeedOperatorCheckField(op->ceed, qf_field, r, b)); 792 CeedCall(CeedCalloc(1, op_field)); 793 794 if (v == CEED_VECTOR_ACTIVE) { 795 CeedSize l_size; 796 797 CeedCall(CeedElemRestrictionGetLVectorSize(r, &l_size)); 798 if (is_input) { 799 if (op->input_size == -1) op->input_size = l_size; 800 CeedCheck(l_size == op->input_size, op->ceed, CEED_ERROR_INCOMPATIBLE, "LVector size %td does not match previous size %td", l_size, 801 op->input_size); 802 } else { 803 if (op->output_size == -1) op->output_size = l_size; 804 CeedCheck(l_size == op->output_size, op->ceed, CEED_ERROR_INCOMPATIBLE, "LVector size %td does not match previous size %td", l_size, 805 op->output_size); 806 } 807 } 808 809 CeedCall(CeedVectorReferenceCopy(v, &(*op_field)->vec)); 810 CeedCall(CeedElemRestrictionReferenceCopy(r, &(*op_field)->elem_rstr)); 811 if (r != CEED_ELEMRESTRICTION_NONE && !op->has_restriction) { 812 op->num_elem = num_elem; 813 op->has_restriction = true; // Restriction set, but num_elem may be 0 814 } 815 CeedCall(CeedBasisReferenceCopy(b, &(*op_field)->basis)); 816 if (op->num_qpts == 0 && !op->is_at_points) op->num_qpts = num_qpts; // no consistent number of qpts for OperatorAtPoints 817 op->num_fields += 1; 818 CeedCall(CeedStringAllocCopy(field_name, (char **)&(*op_field)->field_name)); 819 return CEED_ERROR_SUCCESS; 820 } 821 822 /** 823 @brief Get the CeedOperatorFields of a CeedOperator. 824 825 Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 826 827 @param[in] op CeedOperator 828 @param[out] num_input_fields Variable to store number of input fields 829 @param[out] input_fields Variable to store input_fields 830 @param[out] num_output_fields Variable to store number of output fields 831 @param[out] output_fields Variable to store output_fields 832 833 @return An error code: 0 - success, otherwise - failure 834 835 @ref Advanced 836 **/ 837 int CeedOperatorGetFields(CeedOperator op, CeedInt *num_input_fields, CeedOperatorField **input_fields, CeedInt *num_output_fields, 838 CeedOperatorField **output_fields) { 839 CeedCheck(!op->is_composite, op->ceed, CEED_ERROR_MINOR, "Not defined for composite operator"); 840 CeedCall(CeedOperatorCheckReady(op)); 841 842 if (num_input_fields) *num_input_fields = op->qf->num_input_fields; 843 if (input_fields) *input_fields = op->input_fields; 844 if (num_output_fields) *num_output_fields = op->qf->num_output_fields; 845 if (output_fields) *output_fields = op->output_fields; 846 return CEED_ERROR_SUCCESS; 847 } 848 849 /** 850 @brief Set the arbitrary points in each element for a CeedOperatorAtPoints. 851 852 Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 853 854 @param[in,out] op CeedOperatorAtPoints 855 @param[in] rstr_points CeedElemRestriction for the coordinates of each point by element 856 @param[in] point_coords CeedVector holding coordinates of each point 857 858 @return An error code: 0 - success, otherwise - failure 859 860 @ref Advanced 861 **/ 862 int CeedOperatorAtPointsSetPoints(CeedOperator op, CeedElemRestriction rstr_points, CeedVector point_coords) { 863 CeedCheck(op->is_at_points, op->ceed, CEED_ERROR_MINOR, "Only defined for operator at points"); 864 CeedCheck(!op->is_immutable, op->ceed, CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable"); 865 866 if (!op->first_points_rstr) { 867 CeedCall(CeedElemRestrictionReferenceCopy(rstr_points, &op->first_points_rstr)); 868 } else { 869 bool are_compatible; 870 871 CeedCall(CeedElemRestrictionAtPointsAreCompatible(op->first_points_rstr, rstr_points, &are_compatible)); 872 CeedCheck(are_compatible, op->ceed, CEED_ERROR_INCOMPATIBLE, 873 "ElemRestriction must have compatible offsets with previously set field ElemRestrictions"); 874 } 875 876 CeedCall(CeedElemRestrictionReferenceCopy(rstr_points, &op->rstr_points)); 877 CeedCall(CeedVectorReferenceCopy(point_coords, &op->point_coords)); 878 return CEED_ERROR_SUCCESS; 879 } 880 881 /** 882 @brief Get the arbitrary points in each element for a CeedOperatorAtPoints. 883 884 Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 885 886 @param[in] op CeedOperatorAtPoints 887 @param[out] rstr_points Variable to hold CeedElemRestriction for the coordinates of each point by element 888 @param[out] point_coords Variable to hold CeedVector holding coordinates of each point 889 890 @return An error code: 0 - success, otherwise - failure 891 892 @ref Advanced 893 **/ 894 int CeedOperatorAtPointsGetPoints(CeedOperator op, CeedElemRestriction *rstr_points, CeedVector *point_coords) { 895 CeedCheck(op->is_at_points, op->ceed, CEED_ERROR_MINOR, "Only defined for operator at points"); 896 CeedCall(CeedOperatorCheckReady(op)); 897 898 if (rstr_points) CeedCall(CeedElemRestrictionReferenceCopy(op->rstr_points, rstr_points)); 899 if (point_coords) CeedCall(CeedVectorReferenceCopy(op->point_coords, point_coords)); 900 return CEED_ERROR_SUCCESS; 901 } 902 903 /** 904 @brief Get a CeedOperatorField of an CeedOperator from its name 905 906 Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 907 908 @param[in] op CeedOperator 909 @param[in] field_name Name of desired CeedOperatorField 910 @param[out] op_field CeedOperatorField corresponding to the name 911 912 @return An error code: 0 - success, otherwise - failure 913 914 @ref Advanced 915 **/ 916 int CeedOperatorGetFieldByName(CeedOperator op, const char *field_name, CeedOperatorField *op_field) { 917 char *name; 918 CeedInt num_input_fields, num_output_fields; 919 CeedOperatorField *input_fields, *output_fields; 920 921 CeedCall(CeedOperatorGetFields(op, &num_input_fields, &input_fields, &num_output_fields, &output_fields)); 922 for (CeedInt i = 0; i < num_input_fields; i++) { 923 CeedCall(CeedOperatorFieldGetName(input_fields[i], &name)); 924 if (!strcmp(name, field_name)) { 925 *op_field = input_fields[i]; 926 return CEED_ERROR_SUCCESS; 927 } 928 } 929 for (CeedInt i = 0; i < num_output_fields; i++) { 930 CeedCall(CeedOperatorFieldGetName(output_fields[i], &name)); 931 if (!strcmp(name, field_name)) { 932 *op_field = output_fields[i]; 933 return CEED_ERROR_SUCCESS; 934 } 935 } 936 // LCOV_EXCL_START 937 bool has_name = op->name; 938 939 return CeedError(op->ceed, CEED_ERROR_MINOR, "The field \"%s\" not found in CeedOperator%s%s%s.\n", field_name, has_name ? " \"" : "", 940 has_name ? op->name : "", has_name ? "\"" : ""); 941 // LCOV_EXCL_STOP 942 } 943 944 /** 945 @brief Get the name of a CeedOperatorField 946 947 @param[in] op_field CeedOperatorField 948 @param[out] field_name Variable to store the field name 949 950 @return An error code: 0 - success, otherwise - failure 951 952 @ref Advanced 953 **/ 954 int CeedOperatorFieldGetName(CeedOperatorField op_field, char **field_name) { 955 *field_name = (char *)op_field->field_name; 956 return CEED_ERROR_SUCCESS; 957 } 958 959 /** 960 @brief Get the CeedElemRestriction of a CeedOperatorField 961 962 @param[in] op_field CeedOperatorField 963 @param[out] rstr Variable to store CeedElemRestriction 964 965 @return An error code: 0 - success, otherwise - failure 966 967 @ref Advanced 968 **/ 969 int CeedOperatorFieldGetElemRestriction(CeedOperatorField op_field, CeedElemRestriction *rstr) { 970 *rstr = op_field->elem_rstr; 971 return CEED_ERROR_SUCCESS; 972 } 973 974 /** 975 @brief Get the CeedBasis of a CeedOperatorField 976 977 @param[in] op_field CeedOperatorField 978 @param[out] basis Variable to store CeedBasis 979 980 @return An error code: 0 - success, otherwise - failure 981 982 @ref Advanced 983 **/ 984 int CeedOperatorFieldGetBasis(CeedOperatorField op_field, CeedBasis *basis) { 985 *basis = op_field->basis; 986 return CEED_ERROR_SUCCESS; 987 } 988 989 /** 990 @brief Get the CeedVector of a CeedOperatorField 991 992 @param[in] op_field CeedOperatorField 993 @param[out] vec Variable to store CeedVector 994 995 @return An error code: 0 - success, otherwise - failure 996 997 @ref Advanced 998 **/ 999 int CeedOperatorFieldGetVector(CeedOperatorField op_field, CeedVector *vec) { 1000 *vec = op_field->vec; 1001 return CEED_ERROR_SUCCESS; 1002 } 1003 1004 /** 1005 @brief Add a sub-operator to a composite CeedOperator 1006 1007 @param[in,out] composite_op Composite CeedOperator 1008 @param[in] sub_op Sub-operator CeedOperator 1009 1010 @return An error code: 0 - success, otherwise - failure 1011 1012 @ref User 1013 */ 1014 int CeedCompositeOperatorAddSub(CeedOperator composite_op, CeedOperator sub_op) { 1015 CeedCheck(composite_op->is_composite, composite_op->ceed, CEED_ERROR_MINOR, "CeedOperator is not a composite operator"); 1016 CeedCheck(composite_op->num_suboperators < CEED_COMPOSITE_MAX, composite_op->ceed, CEED_ERROR_UNSUPPORTED, "Cannot add additional sub-operators"); 1017 CeedCheck(!composite_op->is_immutable, composite_op->ceed, CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable"); 1018 1019 { 1020 CeedSize input_size, output_size; 1021 1022 CeedCall(CeedOperatorGetActiveVectorLengths(sub_op, &input_size, &output_size)); 1023 if (composite_op->input_size == -1) composite_op->input_size = input_size; 1024 if (composite_op->output_size == -1) composite_op->output_size = output_size; 1025 // Note, a size of -1 means no active vector restriction set, so no incompatibility 1026 CeedCheck((input_size == -1 || input_size == composite_op->input_size) && (output_size == -1 || output_size == composite_op->output_size), 1027 composite_op->ceed, CEED_ERROR_MAJOR, 1028 "Sub-operators must have compatible dimensions; composite operator of shape (%td, %td) not compatible with sub-operator of " 1029 "shape (%td, %td)", 1030 composite_op->input_size, composite_op->output_size, input_size, output_size); 1031 } 1032 1033 composite_op->sub_operators[composite_op->num_suboperators] = sub_op; 1034 CeedCall(CeedOperatorReference(sub_op)); 1035 composite_op->num_suboperators++; 1036 return CEED_ERROR_SUCCESS; 1037 } 1038 1039 /** 1040 @brief Get the number of sub_operators associated with a CeedOperator 1041 1042 @param[in] op CeedOperator 1043 @param[out] num_suboperators Variable to store number of sub_operators 1044 1045 @return An error code: 0 - success, otherwise - failure 1046 1047 @ref Backend 1048 **/ 1049 int CeedCompositeOperatorGetNumSub(CeedOperator op, CeedInt *num_suboperators) { 1050 CeedCheck(op->is_composite, op->ceed, CEED_ERROR_MINOR, "Only defined for a composite operator"); 1051 *num_suboperators = op->num_suboperators; 1052 return CEED_ERROR_SUCCESS; 1053 } 1054 1055 /** 1056 @brief Get the list of sub_operators associated with a CeedOperator 1057 1058 @param op CeedOperator 1059 @param[out] sub_operators Variable to store list of sub_operators 1060 1061 @return An error code: 0 - success, otherwise - failure 1062 1063 @ref Backend 1064 **/ 1065 int CeedCompositeOperatorGetSubList(CeedOperator op, CeedOperator **sub_operators) { 1066 CeedCheck(op->is_composite, op->ceed, CEED_ERROR_MINOR, "Only defined for a composite operator"); 1067 *sub_operators = op->sub_operators; 1068 return CEED_ERROR_SUCCESS; 1069 } 1070 1071 /** 1072 @brief Check if a CeedOperator is ready to be used. 1073 1074 @param[in] op CeedOperator to check 1075 1076 @return An error code: 0 - success, otherwise - failure 1077 1078 @ref User 1079 **/ 1080 int CeedOperatorCheckReady(CeedOperator op) { 1081 Ceed ceed; 1082 1083 CeedCall(CeedOperatorGetCeed(op, &ceed)); 1084 1085 if (op->is_interface_setup) return CEED_ERROR_SUCCESS; 1086 1087 CeedQFunction qf = op->qf; 1088 if (op->is_composite) { 1089 if (!op->num_suboperators) { 1090 // Empty operator setup 1091 op->input_size = 0; 1092 op->output_size = 0; 1093 } else { 1094 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1095 CeedCall(CeedOperatorCheckReady(op->sub_operators[i])); 1096 } 1097 // Sub-operators could be modified after adding to composite operator 1098 // Need to verify no lvec incompatibility from any changes 1099 CeedSize input_size, output_size; 1100 CeedCall(CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size)); 1101 } 1102 } else { 1103 CeedCheck(op->num_fields > 0, ceed, CEED_ERROR_INCOMPLETE, "No operator fields set"); 1104 CeedCheck(op->num_fields == qf->num_input_fields + qf->num_output_fields, ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set"); 1105 CeedCheck(op->has_restriction, ceed, CEED_ERROR_INCOMPLETE, "At least one restriction required"); 1106 CeedCheck(op->num_qpts > 0 || op->is_at_points, ceed, CEED_ERROR_INCOMPLETE, 1107 "At least one non-collocated basis is required or the number of quadrature points must be set"); 1108 } 1109 1110 // Flag as immutable and ready 1111 op->is_interface_setup = true; 1112 if (op->qf && op->qf != CEED_QFUNCTION_NONE) op->qf->is_immutable = true; 1113 if (op->dqf && op->dqf != CEED_QFUNCTION_NONE) op->dqf->is_immutable = true; 1114 if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE) op->dqfT->is_immutable = true; 1115 return CEED_ERROR_SUCCESS; 1116 } 1117 1118 /** 1119 @brief Get vector lengths for the active input and/or output vectors of a CeedOperator. 1120 1121 Note: Lengths of -1 indicate that the CeedOperator does not have an active input and/or output. 1122 1123 @param[in] op CeedOperator 1124 @param[out] input_size Variable to store active input vector length, or NULL 1125 @param[out] output_size Variable to store active output vector length, or NULL 1126 1127 @return An error code: 0 - success, otherwise - failure 1128 1129 @ref User 1130 **/ 1131 int CeedOperatorGetActiveVectorLengths(CeedOperator op, CeedSize *input_size, CeedSize *output_size) { 1132 bool is_composite; 1133 1134 if (input_size) *input_size = op->input_size; 1135 if (output_size) *output_size = op->output_size; 1136 1137 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1138 if (is_composite && (op->input_size == -1 || op->output_size == -1)) { 1139 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1140 CeedSize sub_input_size, sub_output_size; 1141 1142 CeedCall(CeedOperatorGetActiveVectorLengths(op->sub_operators[i], &sub_input_size, &sub_output_size)); 1143 if (op->input_size == -1) op->input_size = sub_input_size; 1144 if (op->output_size == -1) op->output_size = sub_output_size; 1145 // Note, a size of -1 means no active vector restriction set, so no incompatibility 1146 CeedCheck((sub_input_size == -1 || sub_input_size == op->input_size) && (sub_output_size == -1 || sub_output_size == op->output_size), op->ceed, 1147 CEED_ERROR_MAJOR, 1148 "Sub-operators must have compatible dimensions; composite operator of shape (%td, %td) not compatible with sub-operator of " 1149 "shape (%td, %td)", 1150 op->input_size, op->output_size, input_size, output_size); 1151 } 1152 } 1153 return CEED_ERROR_SUCCESS; 1154 } 1155 1156 /** 1157 @brief Set reuse of CeedQFunction data in CeedOperatorLinearAssemble* functions. 1158 1159 When `reuse_assembly_data = false` (default), the CeedQFunction associated with this CeedOperator is re-assembled every time a 1160 `CeedOperatorLinearAssemble*` function is called. 1161 When `reuse_assembly_data = true`, the CeedQFunction associated with this CeedOperator is reused between calls to 1162 `CeedOperatorSetQFunctionAssemblyDataUpdated`. 1163 1164 @param[in] op CeedOperator 1165 @param[in] reuse_assembly_data Boolean flag setting assembly data reuse 1166 1167 @return An error code: 0 - success, otherwise - failure 1168 1169 @ref Advanced 1170 **/ 1171 int CeedOperatorSetQFunctionAssemblyReuse(CeedOperator op, bool reuse_assembly_data) { 1172 bool is_composite; 1173 1174 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1175 if (is_composite) { 1176 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1177 CeedCall(CeedOperatorSetQFunctionAssemblyReuse(op->sub_operators[i], reuse_assembly_data)); 1178 } 1179 } else { 1180 CeedCall(CeedQFunctionAssemblyDataSetReuse(op->qf_assembled, reuse_assembly_data)); 1181 } 1182 return CEED_ERROR_SUCCESS; 1183 } 1184 1185 /** 1186 @brief Mark CeedQFunction data as updated and the CeedQFunction as requiring re-assembly. 1187 1188 @param[in] op CeedOperator 1189 @param[in] needs_data_update Boolean flag setting assembly data reuse 1190 1191 @return An error code: 0 - success, otherwise - failure 1192 1193 @ref Advanced 1194 **/ 1195 int CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(CeedOperator op, bool needs_data_update) { 1196 bool is_composite; 1197 1198 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1199 if (is_composite) { 1200 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1201 CeedCall(CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(op->sub_operators[i], needs_data_update)); 1202 } 1203 } else { 1204 CeedCall(CeedQFunctionAssemblyDataSetUpdateNeeded(op->qf_assembled, needs_data_update)); 1205 } 1206 return CEED_ERROR_SUCCESS; 1207 } 1208 1209 /** 1210 @brief Set name of CeedOperator for CeedOperatorView output 1211 1212 @param[in,out] op CeedOperator 1213 @param[in] name Name to set, or NULL to remove previously set name 1214 1215 @return An error code: 0 - success, otherwise - failure 1216 1217 @ref User 1218 **/ 1219 int CeedOperatorSetName(CeedOperator op, const char *name) { 1220 char *name_copy; 1221 size_t name_len = name ? strlen(name) : 0; 1222 1223 CeedCall(CeedFree(&op->name)); 1224 if (name_len > 0) { 1225 CeedCall(CeedCalloc(name_len + 1, &name_copy)); 1226 memcpy(name_copy, name, name_len); 1227 op->name = name_copy; 1228 } 1229 return CEED_ERROR_SUCCESS; 1230 } 1231 1232 /** 1233 @brief View a CeedOperator 1234 1235 @param[in] op CeedOperator to view 1236 @param[in] stream Stream to write; typically stdout/stderr or a file 1237 1238 @return Error code: 0 - success, otherwise - failure 1239 1240 @ref User 1241 **/ 1242 int CeedOperatorView(CeedOperator op, FILE *stream) { 1243 bool has_name = op->name; 1244 1245 if (op->is_composite) { 1246 fprintf(stream, "Composite CeedOperator%s%s\n", has_name ? " - " : "", has_name ? op->name : ""); 1247 1248 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1249 has_name = op->sub_operators[i]->name; 1250 fprintf(stream, " SubOperator %" CeedInt_FMT "%s%s:\n", i, has_name ? " - " : "", has_name ? op->sub_operators[i]->name : ""); 1251 CeedCall(CeedOperatorSingleView(op->sub_operators[i], 1, stream)); 1252 } 1253 } else { 1254 fprintf(stream, "CeedOperator%s%s\n", has_name ? " - " : "", has_name ? op->name : ""); 1255 CeedCall(CeedOperatorSingleView(op, 0, stream)); 1256 } 1257 return CEED_ERROR_SUCCESS; 1258 } 1259 1260 /** 1261 @brief Get the Ceed associated with a CeedOperator 1262 1263 @param[in] op CeedOperator 1264 @param[out] ceed Variable to store Ceed 1265 1266 @return An error code: 0 - success, otherwise - failure 1267 1268 @ref Advanced 1269 **/ 1270 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) { 1271 *ceed = op->ceed; 1272 return CEED_ERROR_SUCCESS; 1273 } 1274 1275 /** 1276 @brief Get the number of elements associated with a CeedOperator 1277 1278 @param[in] op CeedOperator 1279 @param[out] num_elem Variable to store number of elements 1280 1281 @return An error code: 0 - success, otherwise - failure 1282 1283 @ref Advanced 1284 **/ 1285 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) { 1286 CeedCheck(!op->is_composite, op->ceed, CEED_ERROR_MINOR, "Not defined for composite operator"); 1287 *num_elem = op->num_elem; 1288 return CEED_ERROR_SUCCESS; 1289 } 1290 1291 /** 1292 @brief Get the number of quadrature points associated with a CeedOperator 1293 1294 @param[in] op CeedOperator 1295 @param[out] num_qpts Variable to store vector number of quadrature points 1296 1297 @return An error code: 0 - success, otherwise - failure 1298 1299 @ref Advanced 1300 **/ 1301 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) { 1302 CeedCheck(!op->is_composite, op->ceed, CEED_ERROR_MINOR, "Not defined for composite operator"); 1303 *num_qpts = op->num_qpts; 1304 return CEED_ERROR_SUCCESS; 1305 } 1306 1307 /** 1308 @brief Estimate number of FLOPs required to apply CeedOperator on the active vector 1309 1310 @param[in] op CeedOperator to estimate FLOPs for 1311 @param[out] flops Address of variable to hold FLOPs estimate 1312 1313 @ref Backend 1314 **/ 1315 int CeedOperatorGetFlopsEstimate(CeedOperator op, CeedSize *flops) { 1316 bool is_composite; 1317 1318 CeedCall(CeedOperatorCheckReady(op)); 1319 1320 *flops = 0; 1321 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1322 if (is_composite) { 1323 CeedInt num_suboperators; 1324 1325 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 1326 CeedOperator *sub_operators; 1327 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1328 1329 // FLOPs for each suboperator 1330 for (CeedInt i = 0; i < num_suboperators; i++) { 1331 CeedSize suboperator_flops; 1332 1333 CeedCall(CeedOperatorGetFlopsEstimate(sub_operators[i], &suboperator_flops)); 1334 *flops += suboperator_flops; 1335 } 1336 } else { 1337 CeedInt num_input_fields, num_output_fields, num_elem = 0; 1338 CeedOperatorField *input_fields, *output_fields; 1339 1340 CeedCall(CeedOperatorGetFields(op, &num_input_fields, &input_fields, &num_output_fields, &output_fields)); 1341 CeedCall(CeedOperatorGetNumElements(op, &num_elem)); 1342 1343 // Input FLOPs 1344 for (CeedInt i = 0; i < num_input_fields; i++) { 1345 if (input_fields[i]->vec == CEED_VECTOR_ACTIVE) { 1346 CeedSize rstr_flops, basis_flops; 1347 1348 CeedCall(CeedElemRestrictionGetFlopsEstimate(input_fields[i]->elem_rstr, CEED_NOTRANSPOSE, &rstr_flops)); 1349 *flops += rstr_flops; 1350 CeedCall(CeedBasisGetFlopsEstimate(input_fields[i]->basis, CEED_NOTRANSPOSE, op->qf->input_fields[i]->eval_mode, &basis_flops)); 1351 *flops += basis_flops * num_elem; 1352 } 1353 } 1354 // QF FLOPs 1355 { 1356 CeedInt num_qpts; 1357 CeedSize qf_flops; 1358 1359 CeedCall(CeedOperatorGetNumQuadraturePoints(op, &num_qpts)); 1360 CeedCall(CeedQFunctionGetFlopsEstimate(op->qf, &qf_flops)); 1361 *flops += num_elem * num_qpts * qf_flops; 1362 } 1363 1364 // Output FLOPs 1365 for (CeedInt i = 0; i < num_output_fields; i++) { 1366 if (output_fields[i]->vec == CEED_VECTOR_ACTIVE) { 1367 CeedSize rstr_flops, basis_flops; 1368 1369 CeedCall(CeedElemRestrictionGetFlopsEstimate(output_fields[i]->elem_rstr, CEED_TRANSPOSE, &rstr_flops)); 1370 *flops += rstr_flops; 1371 CeedCall(CeedBasisGetFlopsEstimate(output_fields[i]->basis, CEED_TRANSPOSE, op->qf->output_fields[i]->eval_mode, &basis_flops)); 1372 *flops += basis_flops * num_elem; 1373 } 1374 } 1375 } 1376 return CEED_ERROR_SUCCESS; 1377 } 1378 1379 /** 1380 @brief Get CeedQFunction global context for a CeedOperator. 1381 1382 The caller is responsible for destroying `ctx` returned from this function via `CeedQFunctionContextDestroy()`. 1383 1384 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. 1385 This CeedQFunctionContext will be destroyed if `ctx` is the only reference to this CeedQFunctionContext. 1386 1387 @param[in] op CeedOperator 1388 @param[out] ctx Variable to store CeedQFunctionContext 1389 1390 @return An error code: 0 - success, otherwise - failure 1391 1392 @ref Advanced 1393 **/ 1394 int CeedOperatorGetContext(CeedOperator op, CeedQFunctionContext *ctx) { 1395 CeedCheck(!op->is_composite, op->ceed, CEED_ERROR_INCOMPATIBLE, "Cannot retrieve QFunctionContext for composite operator"); 1396 if (op->qf->ctx) CeedCall(CeedQFunctionContextReferenceCopy(op->qf->ctx, ctx)); 1397 else *ctx = NULL; 1398 return CEED_ERROR_SUCCESS; 1399 } 1400 1401 /** 1402 @brief Get label for a registered QFunctionContext field, or `NULL` if no field has been registered with this `field_name`. 1403 1404 Fields are registered via `CeedQFunctionContextRegister*()` functions (eg. `CeedQFunctionContextRegisterDouble()`). 1405 1406 @param[in] op CeedOperator 1407 @param[in] field_name Name of field to retrieve label 1408 @param[out] field_label Variable to field label 1409 1410 @return An error code: 0 - success, otherwise - failure 1411 1412 @ref User 1413 **/ 1414 int CeedOperatorGetContextFieldLabel(CeedOperator op, const char *field_name, CeedContextFieldLabel *field_label) { 1415 bool is_composite, field_found = false; 1416 1417 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1418 1419 if (is_composite) { 1420 // Composite operator 1421 // -- Check if composite label already created 1422 for (CeedInt i = 0; i < op->num_context_labels; i++) { 1423 if (!strcmp(op->context_labels[i]->name, field_name)) { 1424 *field_label = op->context_labels[i]; 1425 return CEED_ERROR_SUCCESS; 1426 } 1427 } 1428 1429 // -- Create composite label if needed 1430 CeedInt num_sub; 1431 CeedOperator *sub_operators; 1432 CeedContextFieldLabel new_field_label; 1433 1434 CeedCall(CeedCalloc(1, &new_field_label)); 1435 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_sub)); 1436 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1437 CeedCall(CeedCalloc(num_sub, &new_field_label->sub_labels)); 1438 new_field_label->num_sub_labels = num_sub; 1439 1440 for (CeedInt i = 0; i < num_sub; i++) { 1441 if (sub_operators[i]->qf->ctx) { 1442 CeedContextFieldLabel new_field_label_i; 1443 1444 CeedCall(CeedQFunctionContextGetFieldLabel(sub_operators[i]->qf->ctx, field_name, &new_field_label_i)); 1445 if (new_field_label_i) { 1446 field_found = true; 1447 new_field_label->sub_labels[i] = new_field_label_i; 1448 new_field_label->name = new_field_label_i->name; 1449 new_field_label->description = new_field_label_i->description; 1450 if (new_field_label->type && new_field_label->type != new_field_label_i->type) { 1451 // LCOV_EXCL_START 1452 CeedCall(CeedFree(&new_field_label)); 1453 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, "Incompatible field types on sub-operator contexts. %s != %s", 1454 CeedContextFieldTypes[new_field_label->type], CeedContextFieldTypes[new_field_label_i->type]); 1455 // LCOV_EXCL_STOP 1456 } else { 1457 new_field_label->type = new_field_label_i->type; 1458 } 1459 if (new_field_label->num_values != 0 && new_field_label->num_values != new_field_label_i->num_values) { 1460 // LCOV_EXCL_START 1461 CeedCall(CeedFree(&new_field_label)); 1462 return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, "Incompatible field number of values on sub-operator contexts. %ld != %ld", 1463 new_field_label->num_values, new_field_label_i->num_values); 1464 // LCOV_EXCL_STOP 1465 } else { 1466 new_field_label->num_values = new_field_label_i->num_values; 1467 } 1468 } 1469 } 1470 } 1471 // -- Cleanup if field was found 1472 if (field_found) { 1473 *field_label = new_field_label; 1474 } else { 1475 // LCOV_EXCL_START 1476 CeedCall(CeedFree(&new_field_label->sub_labels)); 1477 CeedCall(CeedFree(&new_field_label)); 1478 *field_label = NULL; 1479 // LCOV_EXCL_STOP 1480 } 1481 } else { 1482 // Single, non-composite operator 1483 if (op->qf->ctx) { 1484 CeedCall(CeedQFunctionContextGetFieldLabel(op->qf->ctx, field_name, field_label)); 1485 } else { 1486 *field_label = NULL; 1487 } 1488 } 1489 1490 // Set label in operator 1491 if (*field_label) { 1492 (*field_label)->from_op = true; 1493 1494 // Move new composite label to operator 1495 if (op->num_context_labels == 0) { 1496 CeedCall(CeedCalloc(1, &op->context_labels)); 1497 op->max_context_labels = 1; 1498 } else if (op->num_context_labels == op->max_context_labels) { 1499 CeedCall(CeedRealloc(2 * op->num_context_labels, &op->context_labels)); 1500 op->max_context_labels *= 2; 1501 } 1502 op->context_labels[op->num_context_labels] = *field_label; 1503 op->num_context_labels++; 1504 } 1505 return CEED_ERROR_SUCCESS; 1506 } 1507 1508 /** 1509 @brief Set QFunctionContext field holding double precision values. 1510 1511 For composite operators, the values are set in all sub-operator QFunctionContexts that have a matching `field_name`. 1512 1513 @param[in,out] op CeedOperator 1514 @param[in] field_label Label of field to set 1515 @param[in] values Values to set 1516 1517 @return An error code: 0 - success, otherwise - failure 1518 1519 @ref User 1520 **/ 1521 int CeedOperatorSetContextDouble(CeedOperator op, CeedContextFieldLabel field_label, double *values) { 1522 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, values); 1523 } 1524 1525 /** 1526 @brief Get QFunctionContext field holding double precision values, read-only. 1527 1528 For composite operators, the values correspond to the first sub-operator QFunctionContexts that has a matching `field_name`. 1529 1530 @param[in] op CeedOperator 1531 @param[in] field_label Label of field to get 1532 @param[out] num_values Number of values in the field label 1533 @param[out] values Pointer to context values 1534 1535 @return An error code: 0 - success, otherwise - failure 1536 1537 @ref User 1538 **/ 1539 int CeedOperatorGetContextDoubleRead(CeedOperator op, CeedContextFieldLabel field_label, size_t *num_values, const double **values) { 1540 return CeedOperatorContextGetGenericRead(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, num_values, values); 1541 } 1542 1543 /** 1544 @brief Restore QFunctionContext field holding double precision values, read-only. 1545 1546 @param[in] op CeedOperator 1547 @param[in] field_label Label of field to restore 1548 @param[out] values Pointer to context values 1549 1550 @return An error code: 0 - success, otherwise - failure 1551 1552 @ref User 1553 **/ 1554 int CeedOperatorRestoreContextDoubleRead(CeedOperator op, CeedContextFieldLabel field_label, const double **values) { 1555 return CeedOperatorContextRestoreGenericRead(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, values); 1556 } 1557 1558 /** 1559 @brief Set QFunctionContext field holding int32 values. 1560 1561 For composite operators, the values are set in all sub-operator QFunctionContexts that have a matching `field_name`. 1562 1563 @param[in,out] op CeedOperator 1564 @param[in] field_label Label of field to set 1565 @param[in] values Values to set 1566 1567 @return An error code: 0 - success, otherwise - failure 1568 1569 @ref User 1570 **/ 1571 int CeedOperatorSetContextInt32(CeedOperator op, CeedContextFieldLabel field_label, int32_t *values) { 1572 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_INT32, values); 1573 } 1574 1575 /** 1576 @brief Get QFunctionContext field holding int32 values, read-only. 1577 1578 For composite operators, the values correspond to the first sub-operator QFunctionContexts that has a matching `field_name`. 1579 1580 @param[in] op CeedOperator 1581 @param[in] field_label Label of field to get 1582 @param[out] num_values Number of int32 values in `values` 1583 @param[out] values Pointer to context values 1584 1585 @return An error code: 0 - success, otherwise - failure 1586 1587 @ref User 1588 **/ 1589 int CeedOperatorGetContextInt32Read(CeedOperator op, CeedContextFieldLabel field_label, size_t *num_values, const int32_t **values) { 1590 return CeedOperatorContextGetGenericRead(op, field_label, CEED_CONTEXT_FIELD_INT32, num_values, values); 1591 } 1592 1593 /** 1594 @brief Restore QFunctionContext field holding int32 values, read-only. 1595 1596 @param[in] op CeedOperator 1597 @param[in] field_label Label of field to get 1598 @param[out] values Pointer to context values 1599 1600 @return An error code: 0 - success, otherwise - failure 1601 1602 @ref User 1603 **/ 1604 int CeedOperatorRestoreContextInt32Read(CeedOperator op, CeedContextFieldLabel field_label, const int32_t **values) { 1605 return CeedOperatorContextRestoreGenericRead(op, field_label, CEED_CONTEXT_FIELD_INT32, values); 1606 } 1607 1608 /** 1609 @brief Set QFunctionContext field holding boolean values. 1610 1611 For composite operators, the values are set in all sub-operator QFunctionContexts that have a matching `field_name`. 1612 1613 @param[in,out] op CeedOperator 1614 @param[in] field_label Label of field to set 1615 @param[in] values Values to set 1616 1617 @return An error code: 0 - success, otherwise - failure 1618 1619 @ref User 1620 **/ 1621 int CeedOperatorSetContextBoolean(CeedOperator op, CeedContextFieldLabel field_label, bool *values) { 1622 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_BOOL, values); 1623 } 1624 1625 /** 1626 @brief Get QFunctionContext field holding boolean values, read-only. 1627 1628 For composite operators, the values correspond to the first sub-operator QFunctionContexts that has a matching `field_name`. 1629 1630 @param[in] op CeedOperator 1631 @param[in] field_label Label of field to get 1632 @param[out] num_values Number of int32 values in `values` 1633 @param[out] values Pointer to context values 1634 1635 @return An error code: 0 - success, otherwise - failure 1636 1637 @ref User 1638 **/ 1639 int CeedOperatorGetContextBooleanRead(CeedOperator op, CeedContextFieldLabel field_label, size_t *num_values, const bool **values) { 1640 return CeedOperatorContextGetGenericRead(op, field_label, CEED_CONTEXT_FIELD_BOOL, num_values, values); 1641 } 1642 1643 /** 1644 @brief Restore QFunctionContext field holding boolean values, read-only. 1645 1646 @param[in] op CeedOperator 1647 @param[in] field_label Label of field to get 1648 @param[out] values Pointer to context values 1649 1650 @return An error code: 0 - success, otherwise - failure 1651 1652 @ref User 1653 **/ 1654 int CeedOperatorRestoreContextBooleanRead(CeedOperator op, CeedContextFieldLabel field_label, const bool **values) { 1655 return CeedOperatorContextRestoreGenericRead(op, field_label, CEED_CONTEXT_FIELD_BOOL, values); 1656 } 1657 1658 /** 1659 @brief Apply CeedOperator to a vector 1660 1661 This computes the action of the operator on the specified (active) input, yielding its (active) output. 1662 All inputs and outputs must be specified using CeedOperatorSetField(). 1663 1664 Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable. 1665 1666 @param[in] op CeedOperator to apply 1667 @param[in] in CeedVector containing input state or @ref CEED_VECTOR_NONE if there are no active inputs 1668 @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 1669 active outputs 1670 @param[in] request Address of CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE 1671 1672 @return An error code: 0 - success, otherwise - failure 1673 1674 @ref User 1675 **/ 1676 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, CeedRequest *request) { 1677 CeedCall(CeedOperatorCheckReady(op)); 1678 1679 if (op->is_composite) { 1680 // Composite Operator 1681 if (op->ApplyComposite) { 1682 CeedCall(op->ApplyComposite(op, in, out, request)); 1683 } else { 1684 CeedInt num_suboperators; 1685 CeedOperator *sub_operators; 1686 1687 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 1688 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1689 1690 // Zero all output vectors 1691 if (out != CEED_VECTOR_NONE) CeedCall(CeedVectorSetValue(out, 0.0)); 1692 for (CeedInt i = 0; i < num_suboperators; i++) { 1693 for (CeedInt j = 0; j < sub_operators[i]->qf->num_output_fields; j++) { 1694 CeedVector vec = sub_operators[i]->output_fields[j]->vec; 1695 1696 if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) { 1697 CeedCall(CeedVectorSetValue(vec, 0.0)); 1698 } 1699 } 1700 } 1701 // Apply 1702 for (CeedInt i = 0; i < num_suboperators; i++) { 1703 CeedCall(CeedOperatorApplyAdd(sub_operators[i], in, out, request)); 1704 } 1705 } 1706 } else { 1707 // Standard Operator 1708 if (op->Apply) { 1709 CeedCall(op->Apply(op, in, out, request)); 1710 } else { 1711 // Zero all output vectors 1712 CeedQFunction qf = op->qf; 1713 1714 for (CeedInt i = 0; i < qf->num_output_fields; i++) { 1715 CeedVector vec = op->output_fields[i]->vec; 1716 1717 if (vec == CEED_VECTOR_ACTIVE) vec = out; 1718 if (vec != CEED_VECTOR_NONE) CeedCall(CeedVectorSetValue(vec, 0.0)); 1719 } 1720 // Apply 1721 if (op->num_elem) CeedCall(op->ApplyAdd(op, in, out, request)); 1722 } 1723 } 1724 return CEED_ERROR_SUCCESS; 1725 } 1726 1727 /** 1728 @brief Apply CeedOperator to a vector and add result to output vector 1729 1730 This computes the action of the operator on the specified (active) input, yielding its (active) output. 1731 All inputs and outputs must be specified using CeedOperatorSetField(). 1732 1733 @param[in] op CeedOperator to apply 1734 @param[in] in CeedVector containing input state or NULL if there are no active inputs 1735 @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 1736 @param[in] request Address of CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE 1737 1738 @return An error code: 0 - success, otherwise - failure 1739 1740 @ref User 1741 **/ 1742 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, CeedRequest *request) { 1743 CeedCall(CeedOperatorCheckReady(op)); 1744 1745 if (op->is_composite) { 1746 // Composite Operator 1747 if (op->ApplyAddComposite) { 1748 CeedCall(op->ApplyAddComposite(op, in, out, request)); 1749 } else { 1750 CeedInt num_suboperators; 1751 CeedOperator *sub_operators; 1752 1753 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 1754 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1755 for (CeedInt i = 0; i < num_suboperators; i++) { 1756 CeedCall(CeedOperatorApplyAdd(sub_operators[i], in, out, request)); 1757 } 1758 } 1759 } else if (op->num_elem) { 1760 // Standard Operator 1761 CeedCall(op->ApplyAdd(op, in, out, request)); 1762 } 1763 return CEED_ERROR_SUCCESS; 1764 } 1765 1766 /** 1767 @brief Destroy a CeedOperator 1768 1769 @param[in,out] op CeedOperator to destroy 1770 1771 @return An error code: 0 - success, otherwise - failure 1772 1773 @ref User 1774 **/ 1775 int CeedOperatorDestroy(CeedOperator *op) { 1776 if (!*op || --(*op)->ref_count > 0) { 1777 *op = NULL; 1778 return CEED_ERROR_SUCCESS; 1779 } 1780 if ((*op)->Destroy) CeedCall((*op)->Destroy(*op)); 1781 CeedCall(CeedDestroy(&(*op)->ceed)); 1782 // Free fields 1783 for (CeedInt i = 0; i < (*op)->num_fields; i++) { 1784 if ((*op)->input_fields[i]) { 1785 if ((*op)->input_fields[i]->elem_rstr != CEED_ELEMRESTRICTION_NONE) { 1786 CeedCall(CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_rstr)); 1787 } 1788 if ((*op)->input_fields[i]->basis != CEED_BASIS_NONE) { 1789 CeedCall(CeedBasisDestroy(&(*op)->input_fields[i]->basis)); 1790 } 1791 if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE && (*op)->input_fields[i]->vec != CEED_VECTOR_NONE) { 1792 CeedCall(CeedVectorDestroy(&(*op)->input_fields[i]->vec)); 1793 } 1794 CeedCall(CeedFree(&(*op)->input_fields[i]->field_name)); 1795 CeedCall(CeedFree(&(*op)->input_fields[i])); 1796 } 1797 } 1798 for (CeedInt i = 0; i < (*op)->num_fields; i++) { 1799 if ((*op)->output_fields[i]) { 1800 CeedCall(CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_rstr)); 1801 if ((*op)->output_fields[i]->basis != CEED_BASIS_NONE) { 1802 CeedCall(CeedBasisDestroy(&(*op)->output_fields[i]->basis)); 1803 } 1804 if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE && (*op)->output_fields[i]->vec != CEED_VECTOR_NONE) { 1805 CeedCall(CeedVectorDestroy(&(*op)->output_fields[i]->vec)); 1806 } 1807 CeedCall(CeedFree(&(*op)->output_fields[i]->field_name)); 1808 CeedCall(CeedFree(&(*op)->output_fields[i])); 1809 } 1810 } 1811 // AtPoints data 1812 CeedCall(CeedVectorDestroy(&(*op)->point_coords)); 1813 CeedCall(CeedElemRestrictionDestroy(&(*op)->rstr_points)); 1814 CeedCall(CeedElemRestrictionDestroy(&(*op)->first_points_rstr)); 1815 // Destroy sub_operators 1816 for (CeedInt i = 0; i < (*op)->num_suboperators; i++) { 1817 if ((*op)->sub_operators[i]) { 1818 CeedCall(CeedOperatorDestroy(&(*op)->sub_operators[i])); 1819 } 1820 } 1821 CeedCall(CeedQFunctionDestroy(&(*op)->qf)); 1822 CeedCall(CeedQFunctionDestroy(&(*op)->dqf)); 1823 CeedCall(CeedQFunctionDestroy(&(*op)->dqfT)); 1824 // Destroy any composite labels 1825 if ((*op)->is_composite) { 1826 for (CeedInt i = 0; i < (*op)->num_context_labels; i++) { 1827 CeedCall(CeedFree(&(*op)->context_labels[i]->sub_labels)); 1828 CeedCall(CeedFree(&(*op)->context_labels[i])); 1829 } 1830 } 1831 CeedCall(CeedFree(&(*op)->context_labels)); 1832 1833 // Destroy fallback 1834 CeedCall(CeedOperatorDestroy(&(*op)->op_fallback)); 1835 1836 // Destroy assembly data 1837 CeedCall(CeedQFunctionAssemblyDataDestroy(&(*op)->qf_assembled)); 1838 CeedCall(CeedOperatorAssemblyDataDestroy(&(*op)->op_assembled)); 1839 1840 CeedCall(CeedFree(&(*op)->input_fields)); 1841 CeedCall(CeedFree(&(*op)->output_fields)); 1842 CeedCall(CeedFree(&(*op)->sub_operators)); 1843 CeedCall(CeedFree(&(*op)->name)); 1844 CeedCall(CeedFree(op)); 1845 return CEED_ERROR_SUCCESS; 1846 } 1847 1848 /// @} 1849