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