1 // Copyright (c) 2017-2024, 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 `CeedQFunction` Field 26 27 @param[in] ceed `Ceed` object for error handling 28 @param[in] qf_field `CeedQFunction` Field matching `CeedOperator` Field 29 @param[in] rstr `CeedOperator` Field `CeedElemRestriction` 30 @param[in] basis `CeedOperator` Field `CeedBasis` 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 rstr, CeedBasis basis) { 37 const char *field_name; 38 CeedInt dim = 1, num_comp = 1, q_comp = 1, rstr_num_comp = 1, size; 39 CeedEvalMode eval_mode; 40 41 // Field data 42 CeedCall(CeedQFunctionFieldGetData(qf_field, &field_name, &size, &eval_mode)); 43 44 // Restriction 45 CeedCheck((rstr == CEED_ELEMRESTRICTION_NONE) == (eval_mode == CEED_EVAL_WEIGHT), ceed, CEED_ERROR_INCOMPATIBLE, 46 "CEED_ELEMRESTRICTION_NONE and CEED_EVAL_WEIGHT must be used together."); 47 if (rstr != CEED_ELEMRESTRICTION_NONE) { 48 CeedCall(CeedElemRestrictionGetNumComponents(rstr, &rstr_num_comp)); 49 } 50 // Basis 51 CeedCheck((basis == CEED_BASIS_NONE) == (eval_mode == CEED_EVAL_NONE), ceed, CEED_ERROR_INCOMPATIBLE, 52 "CEED_BASIS_NONE and CEED_EVAL_NONE must be used together."); 53 if (basis != CEED_BASIS_NONE) { 54 CeedCall(CeedBasisGetDimension(basis, &dim)); 55 CeedCall(CeedBasisGetNumComponents(basis, &num_comp)); 56 CeedCall(CeedBasisGetNumQuadratureComponents(basis, eval_mode, &q_comp)); 57 CeedCheck(rstr == CEED_ELEMRESTRICTION_NONE || rstr_num_comp == num_comp, ceed, CEED_ERROR_DIMENSION, 58 "Field '%s' of size %" CeedInt_FMT " and EvalMode %s: CeedElemRestriction has %" CeedInt_FMT 59 " components, but CeedBasis has %" CeedInt_FMT " components", 60 field_name, size, CeedEvalModes[eval_mode], rstr_num_comp, num_comp); 61 } 62 // Field size 63 switch (eval_mode) { 64 case CEED_EVAL_NONE: 65 CeedCheck(size == rstr_num_comp, ceed, CEED_ERROR_DIMENSION, 66 "Field '%s' of size %" CeedInt_FMT " and EvalMode %s: CeedElemRestriction has %" CeedInt_FMT " components", field_name, size, 67 CeedEvalModes[eval_mode], rstr_num_comp); 68 break; 69 case CEED_EVAL_INTERP: 70 case CEED_EVAL_GRAD: 71 case CEED_EVAL_DIV: 72 case CEED_EVAL_CURL: 73 CeedCheck(size == num_comp * q_comp, ceed, CEED_ERROR_DIMENSION, 74 "Field '%s' of size %" CeedInt_FMT " and EvalMode %s: CeedElemRestriction/Basis has %" CeedInt_FMT " components", field_name, size, 75 CeedEvalModes[eval_mode], num_comp * q_comp); 76 break; 77 case CEED_EVAL_WEIGHT: 78 // No additional checks required 79 break; 80 } 81 return CEED_ERROR_SUCCESS; 82 } 83 84 /** 85 @brief View a field of a `CeedOperator` 86 87 @param[in] op_field `CeedOperator` Field to view 88 @param[in] qf_field `CeedQFunction` Field (carries field name) 89 @param[in] field_number Number of field being viewed 90 @param[in] sub true indicates sub-operator, which increases indentation; false for top-level operator 91 @param[in] input true for an input field; false for output field 92 @param[in] stream Stream to view to, e.g., `stdout` 93 94 @return An error code: 0 - success, otherwise - failure 95 96 @ref Utility 97 **/ 98 static int CeedOperatorFieldView(CeedOperatorField op_field, CeedQFunctionField qf_field, CeedInt field_number, bool sub, bool input, FILE *stream) { 99 const char *pre = sub ? " " : ""; 100 const char *in_out = input ? "Input" : "Output"; 101 const char *field_name; 102 CeedInt size; 103 CeedEvalMode eval_mode; 104 CeedVector vec; 105 CeedBasis basis; 106 107 // Field data 108 CeedCall(CeedQFunctionFieldGetData(qf_field, &field_name, &size, &eval_mode)); 109 CeedCall(CeedOperatorFieldGetData(op_field, NULL, NULL, &basis, &vec)); 110 111 fprintf(stream, 112 "%s %s field %" CeedInt_FMT 113 ":\n" 114 "%s Name: \"%s\"\n", 115 pre, in_out, field_number, pre, field_name); 116 fprintf(stream, "%s Size: %" CeedInt_FMT "\n", pre, size); 117 fprintf(stream, "%s EvalMode: %s\n", pre, CeedEvalModes[eval_mode]); 118 if (basis == CEED_BASIS_NONE) fprintf(stream, "%s No basis\n", pre); 119 if (vec == CEED_VECTOR_ACTIVE) fprintf(stream, "%s Active vector\n", pre); 120 else if (vec == CEED_VECTOR_NONE) fprintf(stream, "%s No vector\n", pre); 121 return CEED_ERROR_SUCCESS; 122 } 123 124 /** 125 @brief View a single `CeedOperator` 126 127 @param[in] op `CeedOperator` to view 128 @param[in] sub Boolean flag for sub-operator 129 @param[in] stream Stream to write; typically `stdout` or a file 130 131 @return Error code: 0 - success, otherwise - failure 132 133 @ref Utility 134 **/ 135 int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) { 136 const char *pre = sub ? " " : ""; 137 CeedInt num_elem, num_qpts, total_fields = 0, num_input_fields, num_output_fields; 138 CeedQFunction qf; 139 CeedQFunctionField *qf_input_fields, *qf_output_fields; 140 CeedOperatorField *op_input_fields, *op_output_fields; 141 142 CeedCall(CeedOperatorGetNumElements(op, &num_elem)); 143 CeedCall(CeedOperatorGetNumQuadraturePoints(op, &num_qpts)); 144 CeedCall(CeedOperatorGetNumArgs(op, &total_fields)); 145 CeedCall(CeedOperatorGetFields(op, &num_input_fields, &op_input_fields, &num_output_fields, &op_output_fields)); 146 CeedCall(CeedOperatorGetQFunction(op, &qf)); 147 CeedCall(CeedQFunctionGetFields(qf, NULL, &qf_input_fields, NULL, &qf_output_fields)); 148 149 fprintf(stream, "%s %" CeedInt_FMT " elements with %" CeedInt_FMT " quadrature points each\n", pre, num_elem, num_qpts); 150 fprintf(stream, "%s %" CeedInt_FMT " field%s\n", pre, total_fields, total_fields > 1 ? "s" : ""); 151 fprintf(stream, "%s %" CeedInt_FMT " input field%s:\n", pre, num_input_fields, num_input_fields > 1 ? "s" : ""); 152 for (CeedInt i = 0; i < num_input_fields; i++) { 153 CeedCall(CeedOperatorFieldView(op_input_fields[i], qf_input_fields[i], i, sub, 1, stream)); 154 } 155 fprintf(stream, "%s %" CeedInt_FMT " output field%s:\n", pre, num_output_fields, num_output_fields > 1 ? "s" : ""); 156 for (CeedInt i = 0; i < num_output_fields; i++) { 157 CeedCall(CeedOperatorFieldView(op_output_fields[i], qf_output_fields[i], i, sub, 0, stream)); 158 } 159 return CEED_ERROR_SUCCESS; 160 } 161 162 /** 163 @brief Find the active input vector `CeedBasis` for a non-composite `CeedOperator` 164 165 @param[in] op `CeedOperator` to find active `CeedBasis` for 166 @param[out] active_basis `CeedBasis` for active input vector or `NULL` for composite operator 167 168 @return An error code: 0 - success, otherwise - failure 169 170 @ref Developer 171 **/ 172 int CeedOperatorGetActiveBasis(CeedOperator op, CeedBasis *active_basis) { 173 CeedCall(CeedOperatorGetActiveBases(op, active_basis, NULL)); 174 return CEED_ERROR_SUCCESS; 175 } 176 177 /** 178 @brief Find the active input and output vector `CeedBasis` for a non-composite `CeedOperator` 179 180 @param[in] op `CeedOperator` to find active `CeedBasis` for 181 @param[out] active_input_basis `CeedBasis` for active input vector or `NULL` for composite operator 182 @param[out] active_output_basis `CeedBasis` for active output vector or `NULL` for composite operator 183 184 @return An error code: 0 - success, otherwise - failure 185 186 @ref Developer 187 **/ 188 int CeedOperatorGetActiveBases(CeedOperator op, CeedBasis *active_input_basis, CeedBasis *active_output_basis) { 189 bool is_composite; 190 CeedInt num_input_fields, num_output_fields; 191 Ceed ceed; 192 CeedOperatorField *op_input_fields, *op_output_fields; 193 194 CeedCall(CeedOperatorGetCeed(op, &ceed)); 195 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 196 CeedCall(CeedOperatorGetFields(op, &num_input_fields, &op_input_fields, &num_output_fields, &op_output_fields)); 197 198 if (active_input_basis) { 199 *active_input_basis = NULL; 200 if (!is_composite) { 201 for (CeedInt i = 0; i < num_input_fields; i++) { 202 CeedVector vec; 203 204 CeedCall(CeedOperatorFieldGetVector(op_input_fields[i], &vec)); 205 if (vec == CEED_VECTOR_ACTIVE) { 206 CeedBasis basis; 207 208 CeedCall(CeedOperatorFieldGetBasis(op_input_fields[i], &basis)); 209 CeedCheck(!*active_input_basis || *active_input_basis == basis, ceed, CEED_ERROR_MINOR, "Multiple active input CeedBases found"); 210 *active_input_basis = basis; 211 } 212 } 213 CeedCheck(*active_input_basis, ceed, CEED_ERROR_INCOMPLETE, "No active input CeedBasis found"); 214 } 215 } 216 if (active_output_basis) { 217 *active_output_basis = NULL; 218 if (!is_composite) { 219 for (CeedInt i = 0; i < num_output_fields; i++) { 220 CeedVector vec; 221 222 CeedCall(CeedOperatorFieldGetVector(op_output_fields[i], &vec)); 223 if (vec == CEED_VECTOR_ACTIVE) { 224 CeedBasis basis; 225 226 CeedCall(CeedOperatorFieldGetBasis(op_output_fields[i], &basis)); 227 CeedCheck(!*active_output_basis || *active_output_basis == basis, ceed, CEED_ERROR_MINOR, "Multiple active output CeedBases found"); 228 *active_output_basis = basis; 229 } 230 } 231 CeedCheck(*active_output_basis, ceed, CEED_ERROR_INCOMPLETE, "No active output CeedBasis found"); 232 } 233 } 234 return CEED_ERROR_SUCCESS; 235 } 236 237 /** 238 @brief Find the active vector `CeedElemRestriction` for a non-composite `CeedOperator` 239 240 @param[in] op `CeedOperator` to find active `CeedElemRestriction` for 241 @param[out] active_rstr `CeedElemRestriction` for active input vector or NULL for composite operator 242 243 @return An error code: 0 - success, otherwise - failure 244 245 @ref Utility 246 **/ 247 int CeedOperatorGetActiveElemRestriction(CeedOperator op, CeedElemRestriction *active_rstr) { 248 CeedCall(CeedOperatorGetActiveElemRestrictions(op, active_rstr, NULL)); 249 return CEED_ERROR_SUCCESS; 250 } 251 252 /** 253 @brief Find the active input and output vector `CeedElemRestriction` for a non-composite `CeedOperator` 254 255 @param[in] op `CeedOperator` to find active `CeedElemRestriction` for 256 @param[out] active_input_rstr `CeedElemRestriction` for active input vector or NULL for composite operator 257 @param[out] active_output_rstr `CeedElemRestriction` for active output vector or NULL for composite operator 258 259 @return An error code: 0 - success, otherwise - failure 260 261 @ref Utility 262 **/ 263 int CeedOperatorGetActiveElemRestrictions(CeedOperator op, CeedElemRestriction *active_input_rstr, CeedElemRestriction *active_output_rstr) { 264 bool is_composite; 265 CeedInt num_input_fields, num_output_fields; 266 Ceed ceed; 267 CeedOperatorField *op_input_fields, *op_output_fields; 268 269 CeedCall(CeedOperatorGetCeed(op, &ceed)); 270 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 271 CeedCall(CeedOperatorGetFields(op, &num_input_fields, &op_input_fields, &num_output_fields, &op_output_fields)); 272 273 if (active_input_rstr) { 274 *active_input_rstr = NULL; 275 if (!is_composite) { 276 for (CeedInt i = 0; i < num_input_fields; i++) { 277 CeedVector vec; 278 279 CeedCall(CeedOperatorFieldGetVector(op_input_fields[i], &vec)); 280 if (vec == CEED_VECTOR_ACTIVE) { 281 CeedElemRestriction rstr; 282 283 CeedCall(CeedOperatorFieldGetElemRestriction(op_input_fields[i], &rstr)); 284 CeedCheck(!*active_input_rstr || *active_input_rstr == rstr, ceed, CEED_ERROR_MINOR, "Multiple active input CeedElemRestrictions found"); 285 *active_input_rstr = rstr; 286 } 287 } 288 CeedCheck(*active_input_rstr, ceed, CEED_ERROR_INCOMPLETE, "No active input CeedElemRestriction found"); 289 } 290 } 291 if (active_output_rstr) { 292 *active_output_rstr = NULL; 293 if (!is_composite) { 294 for (CeedInt i = 0; i < num_output_fields; i++) { 295 CeedVector vec; 296 297 CeedCall(CeedOperatorFieldGetVector(op_output_fields[i], &vec)); 298 if (vec == CEED_VECTOR_ACTIVE) { 299 CeedElemRestriction rstr; 300 301 CeedCall(CeedOperatorFieldGetElemRestriction(op_output_fields[i], &rstr)); 302 CeedCheck(!*active_output_rstr || *active_output_rstr == rstr, ceed, CEED_ERROR_MINOR, "Multiple active output CeedElemRestrictions found"); 303 *active_output_rstr = rstr; 304 } 305 } 306 CeedCheck(*active_output_rstr, ceed, CEED_ERROR_INCOMPLETE, "No active output CeedElemRestriction found"); 307 } 308 } 309 return CEED_ERROR_SUCCESS; 310 } 311 312 /** 313 @brief Set `CeedQFunctionContext` field values of the specified type. 314 315 For composite operators, the value is set in all sub-operator `CeedQFunctionContext` that have a matching `field_name`. 316 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 any field of a matching type. 317 318 @param[in,out] op `CeedOperator` 319 @param[in] field_label Label of field to set 320 @param[in] field_type Type of field to set 321 @param[in] values Values to set 322 323 @return An error code: 0 - success, otherwise - failure 324 325 @ref User 326 **/ 327 static int CeedOperatorContextSetGeneric(CeedOperator op, CeedContextFieldLabel field_label, CeedContextFieldType field_type, void *values) { 328 bool is_composite = false; 329 Ceed ceed; 330 331 CeedCall(CeedOperatorGetCeed(op, &ceed)); 332 CeedCheck(field_label, ceed, CEED_ERROR_UNSUPPORTED, "Invalid field label"); 333 334 // Check if field_label and op correspond 335 if (field_label->from_op) { 336 CeedInt index = -1; 337 338 for (CeedInt i = 0; i < op->num_context_labels; i++) { 339 if (op->context_labels[i] == field_label) index = i; 340 } 341 CeedCheck(index != -1, ceed, CEED_ERROR_UNSUPPORTED, "ContextFieldLabel does not correspond to the operator"); 342 } 343 344 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 345 if (is_composite) { 346 CeedInt num_sub; 347 CeedOperator *sub_operators; 348 349 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_sub)); 350 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 351 CeedCheck(num_sub == field_label->num_sub_labels, ceed, CEED_ERROR_UNSUPPORTED, "Composite operator modified after ContextFieldLabel created"); 352 353 for (CeedInt i = 0; i < num_sub; i++) { 354 CeedQFunction qf; 355 CeedQFunctionContext ctx; 356 357 CeedCall(CeedOperatorGetQFunction(sub_operators[i], &qf)); 358 CeedCall(CeedQFunctionGetContext(qf, &ctx)); 359 // Try every sub-operator, ok if some sub-operators do not have field 360 if (field_label->sub_labels[i] && ctx) { 361 CeedCall(CeedQFunctionContextSetGeneric(ctx, field_label->sub_labels[i], field_type, values)); 362 } 363 } 364 } else { 365 CeedQFunction qf; 366 CeedQFunctionContext ctx; 367 368 CeedCall(CeedOperatorGetQFunction(op, &qf)); 369 CeedCall(CeedQFunctionGetContext(qf, &ctx)); 370 CeedCheck(ctx, ceed, CEED_ERROR_UNSUPPORTED, "QFunction does not have context data"); 371 CeedCall(CeedQFunctionContextSetGeneric(ctx, field_label, field_type, values)); 372 } 373 CeedCall(CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(op, true)); 374 return CEED_ERROR_SUCCESS; 375 } 376 377 /** 378 @brief Get `CeedQFunctionContext` field values of the specified type, read-only. 379 380 For composite operators, the values retrieved are for the first sub-operator `CeedQFunctionContext` that have a matching `field_name`. 381 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 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[out] num_values Number of values of type `field_type` in array `values` 387 @param[out] values Values in the label 388 389 @return An error code: 0 - success, otherwise - failure 390 391 @ref User 392 **/ 393 static int CeedOperatorContextGetGenericRead(CeedOperator op, CeedContextFieldLabel field_label, CeedContextFieldType field_type, size_t *num_values, 394 void *values) { 395 bool is_composite = false; 396 Ceed ceed; 397 398 CeedCall(CeedOperatorGetCeed(op, &ceed)); 399 CeedCheck(field_label, ceed, CEED_ERROR_UNSUPPORTED, "Invalid field label"); 400 401 *(void **)values = NULL; 402 *num_values = 0; 403 404 // Check if field_label and op correspond 405 if (field_label->from_op) { 406 CeedInt index = -1; 407 408 for (CeedInt i = 0; i < op->num_context_labels; i++) { 409 if (op->context_labels[i] == field_label) index = i; 410 } 411 CeedCheck(index != -1, ceed, CEED_ERROR_UNSUPPORTED, "ContextFieldLabel does not correspond to the operator"); 412 } 413 414 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 415 if (is_composite) { 416 CeedInt num_sub; 417 CeedOperator *sub_operators; 418 419 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_sub)); 420 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 421 CeedCheck(num_sub == field_label->num_sub_labels, ceed, CEED_ERROR_UNSUPPORTED, "Composite operator modified after ContextFieldLabel created"); 422 423 for (CeedInt i = 0; i < num_sub; i++) { 424 CeedQFunction qf; 425 CeedQFunctionContext ctx; 426 427 CeedCall(CeedOperatorGetQFunction(sub_operators[i], &qf)); 428 CeedCall(CeedQFunctionGetContext(qf, &ctx)); 429 // Try every sub-operator, ok if some sub-operators do not have field 430 if (field_label->sub_labels[i] && ctx) { 431 CeedCall(CeedQFunctionContextGetGenericRead(ctx, field_label->sub_labels[i], field_type, num_values, values)); 432 return CEED_ERROR_SUCCESS; 433 } 434 } 435 } else { 436 CeedQFunction qf; 437 CeedQFunctionContext ctx; 438 439 CeedCall(CeedOperatorGetQFunction(op, &qf)); 440 CeedCall(CeedQFunctionGetContext(qf, &ctx)); 441 CeedCheck(ctx, ceed, CEED_ERROR_UNSUPPORTED, "QFunction does not have context data"); 442 CeedCall(CeedQFunctionContextGetGenericRead(ctx, field_label, field_type, num_values, values)); 443 } 444 return CEED_ERROR_SUCCESS; 445 } 446 447 /** 448 @brief Restore `CeedQFunctionContext` field values of the specified type, read-only. 449 450 For composite operators, the values restored are for the first sub-operator `CeedQFunctionContext` that have a matching `field_name`. 451 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 any field of a matching type. 452 453 @param[in,out] op `CeedOperator` 454 @param[in] field_label Label of field to set 455 @param[in] field_type Type of field to set 456 @param[in] values Values array to restore 457 458 @return An error code: 0 - success, otherwise - failure 459 460 @ref User 461 **/ 462 static int CeedOperatorContextRestoreGenericRead(CeedOperator op, CeedContextFieldLabel field_label, CeedContextFieldType field_type, void *values) { 463 bool is_composite = false; 464 Ceed ceed; 465 466 CeedCall(CeedOperatorGetCeed(op, &ceed)); 467 CeedCheck(field_label, ceed, CEED_ERROR_UNSUPPORTED, "Invalid field label"); 468 469 // Check if field_label and op correspond 470 if (field_label->from_op) { 471 CeedInt index = -1; 472 473 for (CeedInt i = 0; i < op->num_context_labels; i++) { 474 if (op->context_labels[i] == field_label) index = i; 475 } 476 CeedCheck(index != -1, ceed, CEED_ERROR_UNSUPPORTED, "ContextFieldLabel does not correspond to the operator"); 477 } 478 479 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 480 if (is_composite) { 481 CeedInt num_sub; 482 CeedOperator *sub_operators; 483 484 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_sub)); 485 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 486 CeedCheck(num_sub == field_label->num_sub_labels, ceed, CEED_ERROR_UNSUPPORTED, "Composite operator modified after ContextFieldLabel created"); 487 488 for (CeedInt i = 0; i < num_sub; i++) { 489 CeedQFunction qf; 490 CeedQFunctionContext ctx; 491 492 CeedCall(CeedOperatorGetQFunction(sub_operators[i], &qf)); 493 CeedCall(CeedQFunctionGetContext(qf, &ctx)); 494 // Try every sub-operator, ok if some sub-operators do not have field 495 if (field_label->sub_labels[i] && ctx) { 496 CeedCall(CeedQFunctionContextRestoreGenericRead(ctx, field_label->sub_labels[i], field_type, values)); 497 return CEED_ERROR_SUCCESS; 498 } 499 } 500 } else { 501 CeedQFunction qf; 502 CeedQFunctionContext ctx; 503 504 CeedCall(CeedOperatorGetQFunction(op, &qf)); 505 CeedCall(CeedQFunctionGetContext(qf, &ctx)); 506 CeedCheck(ctx, ceed, CEED_ERROR_UNSUPPORTED, "QFunction does not have context data"); 507 CeedCall(CeedQFunctionContextRestoreGenericRead(ctx, field_label, field_type, values)); 508 } 509 return CEED_ERROR_SUCCESS; 510 } 511 512 /// @} 513 514 /// ---------------------------------------------------------------------------- 515 /// CeedOperator Backend API 516 /// ---------------------------------------------------------------------------- 517 /// @addtogroup CeedOperatorBackend 518 /// @{ 519 520 /** 521 @brief Get the number of arguments associated with a `CeedOperator` 522 523 @param[in] op `CeedOperator` 524 @param[out] num_args Variable to store vector number of arguments 525 526 @return An error code: 0 - success, otherwise - failure 527 528 @ref Backend 529 **/ 530 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *num_args) { 531 bool is_composite; 532 533 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 534 CeedCheck(!is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Not defined for composite operators"); 535 *num_args = op->num_fields; 536 return CEED_ERROR_SUCCESS; 537 } 538 539 /** 540 @brief Get the tensor product status of all bases for a `CeedOperator`. 541 542 `has_tensor_bases` is only set to `true` if every field uses a tensor-product basis. 543 544 @param[in] op `CeedOperator` 545 @param[out] has_tensor_bases Variable to store tensor bases status 546 547 @return An error code: 0 - success, otherwise - failure 548 549 @ref Backend 550 **/ 551 int CeedOperatorHasTensorBases(CeedOperator op, bool *has_tensor_bases) { 552 CeedInt num_inputs, num_outputs; 553 CeedOperatorField *input_fields, *output_fields; 554 555 CeedCall(CeedOperatorGetFields(op, &num_inputs, &input_fields, &num_outputs, &output_fields)); 556 *has_tensor_bases = true; 557 for (CeedInt i = 0; i < num_inputs; i++) { 558 bool is_tensor; 559 CeedBasis basis; 560 561 CeedCall(CeedOperatorFieldGetBasis(input_fields[i], &basis)); 562 if (basis != CEED_BASIS_NONE) { 563 CeedCall(CeedBasisIsTensor(basis, &is_tensor)); 564 *has_tensor_bases &= is_tensor; 565 } 566 } 567 for (CeedInt i = 0; i < num_outputs; i++) { 568 bool is_tensor; 569 CeedBasis basis; 570 571 CeedCall(CeedOperatorFieldGetBasis(output_fields[i], &basis)); 572 if (basis != CEED_BASIS_NONE) { 573 CeedCall(CeedBasisIsTensor(basis, &is_tensor)); 574 *has_tensor_bases &= is_tensor; 575 } 576 } 577 return CEED_ERROR_SUCCESS; 578 } 579 580 /** 581 @brief Get a boolean value indicating if the `CeedOperator` is immutable 582 583 @param[in] op `CeedOperator` 584 @param[out] is_immutable Variable to store immutability status 585 586 @return An error code: 0 - success, otherwise - failure 587 588 @ref Backend 589 **/ 590 int CeedOperatorIsImmutable(CeedOperator op, bool *is_immutable) { 591 *is_immutable = op->is_immutable; 592 return CEED_ERROR_SUCCESS; 593 } 594 595 /** 596 @brief Get the setup status of a `CeedOperator` 597 598 @param[in] op `CeedOperator` 599 @param[out] is_setup_done Variable to store setup status 600 601 @return An error code: 0 - success, otherwise - failure 602 603 @ref Backend 604 **/ 605 int CeedOperatorIsSetupDone(CeedOperator op, bool *is_setup_done) { 606 *is_setup_done = op->is_backend_setup; 607 return CEED_ERROR_SUCCESS; 608 } 609 610 /** 611 @brief Get the `CeedQFunction` associated with a `CeedOperator` 612 613 @param[in] op `CeedOperator` 614 @param[out] qf Variable to store `CeedQFunction` 615 616 @return An error code: 0 - success, otherwise - failure 617 618 @ref Backend 619 **/ 620 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) { 621 bool is_composite; 622 623 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 624 CeedCheck(!is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Not defined for composite operator"); 625 *qf = op->qf; 626 return CEED_ERROR_SUCCESS; 627 } 628 629 /** 630 @brief Get a boolean value indicating if the `CeedOperator` is composite 631 632 @param[in] op `CeedOperator` 633 @param[out] is_composite Variable to store composite status 634 635 @return An error code: 0 - success, otherwise - failure 636 637 @ref Backend 638 **/ 639 int CeedOperatorIsComposite(CeedOperator op, bool *is_composite) { 640 *is_composite = op->is_composite; 641 return CEED_ERROR_SUCCESS; 642 } 643 644 /** 645 @brief Get the backend data of a `CeedOperator` 646 647 @param[in] op `CeedOperator` 648 @param[out] data Variable to store data 649 650 @return An error code: 0 - success, otherwise - failure 651 652 @ref Backend 653 **/ 654 int CeedOperatorGetData(CeedOperator op, void *data) { 655 *(void **)data = op->data; 656 return CEED_ERROR_SUCCESS; 657 } 658 659 /** 660 @brief Set the backend data of a `CeedOperator` 661 662 @param[in,out] op `CeedOperator` 663 @param[in] data Data to set 664 665 @return An error code: 0 - success, otherwise - failure 666 667 @ref Backend 668 **/ 669 int CeedOperatorSetData(CeedOperator op, void *data) { 670 op->data = data; 671 return CEED_ERROR_SUCCESS; 672 } 673 674 /** 675 @brief Increment the reference counter for a `CeedOperator` 676 677 @param[in,out] op `CeedOperator` to increment the reference counter 678 679 @return An error code: 0 - success, otherwise - failure 680 681 @ref Backend 682 **/ 683 int CeedOperatorReference(CeedOperator op) { 684 op->ref_count++; 685 return CEED_ERROR_SUCCESS; 686 } 687 688 /** 689 @brief Set the setup flag of a `CeedOperator` to `true` 690 691 @param[in,out] op `CeedOperator` 692 693 @return An error code: 0 - success, otherwise - failure 694 695 @ref Backend 696 **/ 697 int CeedOperatorSetSetupDone(CeedOperator op) { 698 op->is_backend_setup = true; 699 return CEED_ERROR_SUCCESS; 700 } 701 702 /// @} 703 704 /// ---------------------------------------------------------------------------- 705 /// CeedOperator Public API 706 /// ---------------------------------------------------------------------------- 707 /// @addtogroup CeedOperatorUser 708 /// @{ 709 710 /** 711 @brief Create a `CeedOperator` and associate a `CeedQFunction`. 712 713 A `CeedBasis` and `CeedElemRestriction` can be associated with `CeedQFunction` fields with @ref CeedOperatorSetField(). 714 715 @param[in] ceed `Ceed` object used to create the `CeedOperator` 716 @param[in] qf `CeedQFunction` defining the action of the operator at quadrature points 717 @param[in] dqf `CeedQFunction` defining the action of the Jacobian of `qf` (or @ref CEED_QFUNCTION_NONE) 718 @param[in] dqfT `CeedQFunction` defining the action of the transpose of the Jacobian of `qf` (or @ref CEED_QFUNCTION_NONE) 719 @param[out] op Address of the variable where the newly created `CeedOperator` will be stored 720 721 @return An error code: 0 - success, otherwise - failure 722 723 @ref User 724 */ 725 int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, CeedQFunction dqfT, CeedOperator *op) { 726 if (!ceed->OperatorCreate) { 727 Ceed delegate; 728 729 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Operator")); 730 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedOperatorCreate"); 731 CeedCall(CeedOperatorCreate(delegate, qf, dqf, dqfT, op)); 732 return CEED_ERROR_SUCCESS; 733 } 734 735 CeedCheck(qf && qf != CEED_QFUNCTION_NONE, ceed, CEED_ERROR_MINOR, "Operator must have a valid CeedQFunction."); 736 737 CeedCall(CeedCalloc(1, op)); 738 CeedCall(CeedReferenceCopy(ceed, &(*op)->ceed)); 739 (*op)->ref_count = 1; 740 (*op)->input_size = -1; 741 (*op)->output_size = -1; 742 CeedCall(CeedQFunctionReferenceCopy(qf, &(*op)->qf)); 743 if (dqf && dqf != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionReferenceCopy(dqf, &(*op)->dqf)); 744 if (dqfT && dqfT != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionReferenceCopy(dqfT, &(*op)->dqfT)); 745 CeedCall(CeedQFunctionAssemblyDataCreate(ceed, &(*op)->qf_assembled)); 746 CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*op)->input_fields)); 747 CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*op)->output_fields)); 748 CeedCall(ceed->OperatorCreate(*op)); 749 return CEED_ERROR_SUCCESS; 750 } 751 752 /** 753 @brief Create a `CeedOperator` for evaluation at evaluation at arbitrary points in each element. 754 755 A `CeedBasis` and `CeedElemRestriction` can be associated with `CeedQFunction` fields with `CeedOperator` SetField. 756 The locations of each point are set with @ref CeedOperatorAtPointsSetPoints(). 757 758 @param[in] ceed `Ceed` object used to create the `CeedOperator` 759 @param[in] qf `CeedQFunction` defining the action of the operator at quadrature points 760 @param[in] dqf `CeedQFunction` defining the action of the Jacobian of @a qf (or @ref CEED_QFUNCTION_NONE) 761 @param[in] dqfT `CeedQFunction` defining the action of the transpose of the Jacobian of @a qf (or @ref CEED_QFUNCTION_NONE) 762 @param[out] op Address of the variable where the newly created CeedOperator will be stored 763 764 @return An error code: 0 - success, otherwise - failure 765 766 @ref User 767 */ 768 int CeedOperatorCreateAtPoints(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, CeedQFunction dqfT, CeedOperator *op) { 769 if (!ceed->OperatorCreateAtPoints) { 770 Ceed delegate; 771 772 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Operator")); 773 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedOperatorCreateAtPoints"); 774 CeedCall(CeedOperatorCreateAtPoints(delegate, qf, dqf, dqfT, op)); 775 return CEED_ERROR_SUCCESS; 776 } 777 778 CeedCheck(qf && qf != CEED_QFUNCTION_NONE, ceed, CEED_ERROR_MINOR, "Operator must have a valid CeedQFunction."); 779 780 CeedCall(CeedCalloc(1, op)); 781 CeedCall(CeedReferenceCopy(ceed, &(*op)->ceed)); 782 (*op)->ref_count = 1; 783 (*op)->is_at_points = true; 784 (*op)->input_size = -1; 785 (*op)->output_size = -1; 786 CeedCall(CeedQFunctionReferenceCopy(qf, &(*op)->qf)); 787 if (dqf && dqf != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionReferenceCopy(dqf, &(*op)->dqf)); 788 if (dqfT && dqfT != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionReferenceCopy(dqfT, &(*op)->dqfT)); 789 CeedCall(CeedQFunctionAssemblyDataCreate(ceed, &(*op)->qf_assembled)); 790 CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*op)->input_fields)); 791 CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*op)->output_fields)); 792 CeedCall(ceed->OperatorCreateAtPoints(*op)); 793 return CEED_ERROR_SUCCESS; 794 } 795 796 /** 797 @brief Create a composite `CeedOperator` that composes the action of several `CeedOperator` 798 799 @param[in] ceed `Ceed` object used to create the `CeedOperator` 800 @param[out] op Address of the variable where the newly created composite `CeedOperator` will be stored 801 802 @return An error code: 0 - success, otherwise - failure 803 804 @ref User 805 */ 806 int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) { 807 if (!ceed->CompositeOperatorCreate) { 808 Ceed delegate; 809 810 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Operator")); 811 if (delegate) { 812 CeedCall(CeedCompositeOperatorCreate(delegate, op)); 813 return CEED_ERROR_SUCCESS; 814 } 815 } 816 817 CeedCall(CeedCalloc(1, op)); 818 CeedCall(CeedReferenceCopy(ceed, &(*op)->ceed)); 819 (*op)->ref_count = 1; 820 (*op)->is_composite = true; 821 CeedCall(CeedCalloc(CEED_COMPOSITE_MAX, &(*op)->sub_operators)); 822 (*op)->input_size = -1; 823 (*op)->output_size = -1; 824 825 if (ceed->CompositeOperatorCreate) CeedCall(ceed->CompositeOperatorCreate(*op)); 826 return CEED_ERROR_SUCCESS; 827 } 828 829 /** 830 @brief Copy the pointer to a `CeedOperator`. 831 832 Both pointers should be destroyed with @ref CeedOperatorDestroy(). 833 834 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`. 835 This `CeedOperator` will be destroyed if `*op_copy` is the only reference to this `CeedOperator`. 836 837 @param[in] op `CeedOperator` to copy reference to 838 @param[in,out] op_copy Variable to store copied reference 839 840 @return An error code: 0 - success, otherwise - failure 841 842 @ref User 843 **/ 844 int CeedOperatorReferenceCopy(CeedOperator op, CeedOperator *op_copy) { 845 CeedCall(CeedOperatorReference(op)); 846 CeedCall(CeedOperatorDestroy(op_copy)); 847 *op_copy = op; 848 return CEED_ERROR_SUCCESS; 849 } 850 851 /** 852 @brief Provide a field to a `CeedOperator` for use by its `CeedQFunction`. 853 854 This function is used to specify both active and passive fields to a `CeedOperator`. 855 For passive fields, a `CeedVector` `vec` must be provided. 856 Passive fields can inputs or outputs (updated in-place when operator is applied). 857 858 Active fields must be specified using this function, but their data (in a `CeedVector`) is passed in @ref CeedOperatorApply(). 859 There can be at most one active input `CeedVector` and at most one active output@ref CeedVector passed to @ref CeedOperatorApply(). 860 861 The number of quadrature points must agree across all points. 862 When using @ref CEED_BASIS_NONE, the number of quadrature points is determined by the element size of `rstr`. 863 864 @param[in,out] op `CeedOperator` on which to provide the field 865 @param[in] field_name Name of the field (to be matched with the name used by `CeedQFunction`) 866 @param[in] rstr `CeedElemRestriction` 867 @param[in] basis `CeedBasis` in which the field resides or @ref CEED_BASIS_NONE if collocated with quadrature points 868 @param[in] vec `CeedVector` to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE if field is active or @ref CEED_VECTOR_NONE if using @ref CEED_EVAL_WEIGHT in the `CeedQFunction` 869 870 @return An error code: 0 - success, otherwise - failure 871 872 @ref User 873 **/ 874 int CeedOperatorSetField(CeedOperator op, const char *field_name, CeedElemRestriction rstr, CeedBasis basis, CeedVector vec) { 875 bool is_input = true, is_at_points, is_composite, is_immutable; 876 CeedInt num_elem = 0, num_qpts = 0, num_input_fields, num_output_fields; 877 Ceed ceed; 878 CeedQFunction qf; 879 CeedQFunctionField qf_field, *qf_input_fields, *qf_output_fields; 880 CeedOperatorField *op_field; 881 882 CeedCall(CeedOperatorGetCeed(op, &ceed)); 883 CeedCall(CeedOperatorIsAtPoints(op, &is_at_points)); 884 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 885 CeedCall(CeedOperatorIsImmutable(op, &is_immutable)); 886 CeedCheck(!is_composite, ceed, CEED_ERROR_INCOMPATIBLE, "Cannot add field to composite operator."); 887 CeedCheck(!is_immutable, ceed, CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable"); 888 CeedCheck(rstr, ceed, CEED_ERROR_INCOMPATIBLE, "CeedElemRestriction rstr for field \"%s\" must be non-NULL.", field_name); 889 CeedCheck(basis, ceed, CEED_ERROR_INCOMPATIBLE, "CeedBasis basis for field \"%s\" must be non-NULL.", field_name); 890 CeedCheck(vec, ceed, CEED_ERROR_INCOMPATIBLE, "CeedVector vec for field \"%s\" must be non-NULL.", field_name); 891 892 CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem)); 893 CeedCheck(rstr == CEED_ELEMRESTRICTION_NONE || !op->has_restriction || num_elem == op->num_elem, ceed, CEED_ERROR_DIMENSION, 894 "CeedElemRestriction with %" CeedInt_FMT " elements incompatible with prior %" CeedInt_FMT " elements", num_elem, op->num_elem); 895 { 896 CeedRestrictionType rstr_type; 897 898 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 899 if (rstr_type == CEED_RESTRICTION_POINTS) { 900 CeedCheck(is_at_points, ceed, CEED_ERROR_UNSUPPORTED, "CeedElemRestriction AtPoints not supported for standard operator fields"); 901 CeedCheck(basis == CEED_BASIS_NONE, ceed, CEED_ERROR_UNSUPPORTED, "CeedElemRestriction AtPoints must be used with CEED_BASIS_NONE"); 902 if (!op->first_points_rstr) { 903 CeedCall(CeedElemRestrictionReferenceCopy(rstr, &op->first_points_rstr)); 904 } else { 905 bool are_compatible; 906 907 CeedCall(CeedElemRestrictionAtPointsAreCompatible(op->first_points_rstr, rstr, &are_compatible)); 908 CeedCheck(are_compatible, ceed, CEED_ERROR_INCOMPATIBLE, 909 "CeedElemRestriction must have compatible offsets with previously set CeedElemRestriction"); 910 } 911 } 912 } 913 914 if (basis == CEED_BASIS_NONE) CeedCall(CeedElemRestrictionGetElementSize(rstr, &num_qpts)); 915 else CeedCall(CeedBasisGetNumQuadraturePoints(basis, &num_qpts)); 916 CeedCheck(op->num_qpts == 0 || num_qpts == op->num_qpts, ceed, CEED_ERROR_DIMENSION, 917 "%s must correspond to the same number of quadrature points as previously added CeedBases. Found %" CeedInt_FMT 918 " quadrature points but expected %" CeedInt_FMT " quadrature points.", 919 basis == CEED_BASIS_NONE ? "CeedElemRestriction" : "CeedBasis", num_qpts, op->num_qpts); 920 921 CeedCall(CeedOperatorGetQFunction(op, &qf)); 922 CeedCall(CeedQFunctionGetFields(qf, &num_input_fields, &qf_input_fields, &num_output_fields, &qf_output_fields)); 923 for (CeedInt i = 0; i < num_input_fields; i++) { 924 const char *qf_field_name; 925 926 CeedCall(CeedQFunctionFieldGetName(qf_input_fields[i], &qf_field_name)); 927 if (!strcmp(field_name, qf_field_name)) { 928 qf_field = qf_input_fields[i]; 929 op_field = &op->input_fields[i]; 930 goto found; 931 } 932 } 933 is_input = false; 934 for (CeedInt i = 0; i < num_output_fields; i++) { 935 const char *qf_field_name; 936 937 CeedCall(CeedQFunctionFieldGetName(qf_output_fields[i], &qf_field_name)); 938 if (!strcmp(field_name, qf_field_name)) { 939 qf_field = qf_output_fields[i]; 940 op_field = &op->output_fields[i]; 941 goto found; 942 } 943 } 944 // LCOV_EXCL_START 945 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "CeedQFunction has no knowledge of field '%s'", field_name); 946 // LCOV_EXCL_STOP 947 found: 948 CeedCall(CeedOperatorCheckField(ceed, qf_field, rstr, basis)); 949 CeedCall(CeedCalloc(1, op_field)); 950 951 if (vec == CEED_VECTOR_ACTIVE) { 952 CeedSize l_size; 953 954 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &l_size)); 955 if (is_input) { 956 if (op->input_size == -1) op->input_size = l_size; 957 CeedCheck(l_size == op->input_size, ceed, CEED_ERROR_INCOMPATIBLE, 958 "LVector size %" CeedSize_FMT " does not match previous size %" CeedSize_FMT "", l_size, op->input_size); 959 } else { 960 if (op->output_size == -1) op->output_size = l_size; 961 CeedCheck(l_size == op->output_size, ceed, CEED_ERROR_INCOMPATIBLE, 962 "LVector size %" CeedSize_FMT " does not match previous size %" CeedSize_FMT "", l_size, op->output_size); 963 } 964 } 965 966 CeedCall(CeedVectorReferenceCopy(vec, &(*op_field)->vec)); 967 CeedCall(CeedElemRestrictionReferenceCopy(rstr, &(*op_field)->elem_rstr)); 968 if (rstr != CEED_ELEMRESTRICTION_NONE && !op->has_restriction) { 969 op->num_elem = num_elem; 970 op->has_restriction = true; // Restriction set, but num_elem may be 0 971 } 972 CeedCall(CeedBasisReferenceCopy(basis, &(*op_field)->basis)); 973 if (op->num_qpts == 0 && !is_at_points) op->num_qpts = num_qpts; // no consistent number of qpts for OperatorAtPoints 974 op->num_fields += 1; 975 CeedCall(CeedStringAllocCopy(field_name, (char **)&(*op_field)->field_name)); 976 return CEED_ERROR_SUCCESS; 977 } 978 979 /** 980 @brief Get the `CeedOperator` Field of a `CeedOperator`. 981 982 Note: Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable. 983 984 @param[in] op `CeedOperator` 985 @param[out] num_input_fields Variable to store number of input fields 986 @param[out] input_fields Variable to store input fields 987 @param[out] num_output_fields Variable to store number of output fields 988 @param[out] output_fields Variable to store output fields 989 990 @return An error code: 0 - success, otherwise - failure 991 992 @ref Advanced 993 **/ 994 int CeedOperatorGetFields(CeedOperator op, CeedInt *num_input_fields, CeedOperatorField **input_fields, CeedInt *num_output_fields, 995 CeedOperatorField **output_fields) { 996 bool is_composite; 997 CeedQFunction qf; 998 999 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1000 CeedCheck(!is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Not defined for composite operator"); 1001 CeedCall(CeedOperatorCheckReady(op)); 1002 1003 CeedCall(CeedOperatorGetQFunction(op, &qf)); 1004 CeedCall(CeedQFunctionGetFields(qf, num_input_fields, NULL, num_output_fields, NULL)); 1005 if (input_fields) *input_fields = op->input_fields; 1006 if (output_fields) *output_fields = op->output_fields; 1007 return CEED_ERROR_SUCCESS; 1008 } 1009 1010 /** 1011 @brief Set the arbitrary points in each element for a `CeedOperator` at points. 1012 1013 Note: Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable. 1014 1015 @param[in,out] op `CeedOperator` at points 1016 @param[in] rstr_points `CeedElemRestriction` for the coordinates of each point by element 1017 @param[in] point_coords `CeedVector` holding coordinates of each point 1018 1019 @return An error code: 0 - success, otherwise - failure 1020 1021 @ref Advanced 1022 **/ 1023 int CeedOperatorAtPointsSetPoints(CeedOperator op, CeedElemRestriction rstr_points, CeedVector point_coords) { 1024 bool is_at_points, is_immutable; 1025 Ceed ceed; 1026 1027 CeedCall(CeedOperatorGetCeed(op, &ceed)); 1028 CeedCall(CeedOperatorIsAtPoints(op, &is_at_points)); 1029 CeedCall(CeedOperatorIsImmutable(op, &is_immutable)); 1030 CeedCheck(is_at_points, ceed, CEED_ERROR_MINOR, "Only defined for operator at points"); 1031 CeedCheck(!is_immutable, ceed, CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable"); 1032 1033 if (!op->first_points_rstr) { 1034 CeedCall(CeedElemRestrictionReferenceCopy(rstr_points, &op->first_points_rstr)); 1035 } else { 1036 bool are_compatible; 1037 1038 CeedCall(CeedElemRestrictionAtPointsAreCompatible(op->first_points_rstr, rstr_points, &are_compatible)); 1039 CeedCheck(are_compatible, ceed, CEED_ERROR_INCOMPATIBLE, 1040 "CeedElemRestriction must have compatible offsets with previously set field CeedElemRestriction"); 1041 } 1042 1043 CeedCall(CeedElemRestrictionReferenceCopy(rstr_points, &op->rstr_points)); 1044 CeedCall(CeedVectorReferenceCopy(point_coords, &op->point_coords)); 1045 return CEED_ERROR_SUCCESS; 1046 } 1047 1048 /** 1049 @brief Get a boolean value indicating if the `CeedOperator` was created with `CeedOperatorCreateAtPoints` 1050 1051 @param[in] op `CeedOperator` 1052 @param[out] is_at_points Variable to store at points status 1053 1054 @return An error code: 0 - success, otherwise - failure 1055 1056 @ref User 1057 **/ 1058 int CeedOperatorIsAtPoints(CeedOperator op, bool *is_at_points) { 1059 *is_at_points = op->is_at_points; 1060 return CEED_ERROR_SUCCESS; 1061 } 1062 1063 /** 1064 @brief Get the arbitrary points in each element for a `CeedOperator` at points. 1065 1066 Note: Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable. 1067 1068 @param[in] op `CeedOperator` at points 1069 @param[out] rstr_points Variable to hold `CeedElemRestriction` for the coordinates of each point by element 1070 @param[out] point_coords Variable to hold `CeedVector` holding coordinates of each point 1071 1072 @return An error code: 0 - success, otherwise - failure 1073 1074 @ref Advanced 1075 **/ 1076 int CeedOperatorAtPointsGetPoints(CeedOperator op, CeedElemRestriction *rstr_points, CeedVector *point_coords) { 1077 bool is_at_points; 1078 1079 CeedCall(CeedOperatorIsAtPoints(op, &is_at_points)); 1080 CeedCheck(is_at_points, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Only defined for operator at points"); 1081 CeedCall(CeedOperatorCheckReady(op)); 1082 1083 if (rstr_points) CeedCall(CeedElemRestrictionReferenceCopy(op->rstr_points, rstr_points)); 1084 if (point_coords) CeedCall(CeedVectorReferenceCopy(op->point_coords, point_coords)); 1085 return CEED_ERROR_SUCCESS; 1086 } 1087 1088 /** 1089 @brief Get a `CeedOperator` Field of a `CeedOperator` from its name. 1090 1091 `op_field` is set to `NULL` if the field is not found. 1092 1093 Note: Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable. 1094 1095 @param[in] op `CeedOperator` 1096 @param[in] field_name Name of desired `CeedOperator` Field 1097 @param[out] op_field `CeedOperator` Field corresponding to the name 1098 1099 @return An error code: 0 - success, otherwise - failure 1100 1101 @ref Advanced 1102 **/ 1103 int CeedOperatorGetFieldByName(CeedOperator op, const char *field_name, CeedOperatorField *op_field) { 1104 const char *name; 1105 CeedInt num_input_fields, num_output_fields; 1106 CeedOperatorField *input_fields, *output_fields; 1107 1108 *op_field = NULL; 1109 CeedCall(CeedOperatorGetFields(op, &num_input_fields, &input_fields, &num_output_fields, &output_fields)); 1110 for (CeedInt i = 0; i < num_input_fields; i++) { 1111 CeedCall(CeedOperatorFieldGetName(input_fields[i], &name)); 1112 if (!strcmp(name, field_name)) { 1113 *op_field = input_fields[i]; 1114 return CEED_ERROR_SUCCESS; 1115 } 1116 } 1117 for (CeedInt i = 0; i < num_output_fields; i++) { 1118 CeedCall(CeedOperatorFieldGetName(output_fields[i], &name)); 1119 if (!strcmp(name, field_name)) { 1120 *op_field = output_fields[i]; 1121 return CEED_ERROR_SUCCESS; 1122 } 1123 } 1124 return CEED_ERROR_SUCCESS; 1125 } 1126 1127 /** 1128 @brief Get the name of a `CeedOperator` Field 1129 1130 @param[in] op_field `CeedOperator` Field 1131 @param[out] field_name Variable to store the field name 1132 1133 @return An error code: 0 - success, otherwise - failure 1134 1135 @ref Advanced 1136 **/ 1137 int CeedOperatorFieldGetName(CeedOperatorField op_field, const char **field_name) { 1138 *field_name = op_field->field_name; 1139 return CEED_ERROR_SUCCESS; 1140 } 1141 1142 /** 1143 @brief Get the `CeedElemRestriction` of a `CeedOperator` Field 1144 1145 @param[in] op_field `CeedOperator` Field 1146 @param[out] rstr Variable to store `CeedElemRestriction` 1147 1148 @return An error code: 0 - success, otherwise - failure 1149 1150 @ref Advanced 1151 **/ 1152 int CeedOperatorFieldGetElemRestriction(CeedOperatorField op_field, CeedElemRestriction *rstr) { 1153 *rstr = op_field->elem_rstr; 1154 return CEED_ERROR_SUCCESS; 1155 } 1156 1157 /** 1158 @brief Get the `CeedBasis` of a `CeedOperator` Field 1159 1160 @param[in] op_field `CeedOperator` Field 1161 @param[out] basis Variable to store `CeedBasis` 1162 1163 @return An error code: 0 - success, otherwise - failure 1164 1165 @ref Advanced 1166 **/ 1167 int CeedOperatorFieldGetBasis(CeedOperatorField op_field, CeedBasis *basis) { 1168 *basis = op_field->basis; 1169 return CEED_ERROR_SUCCESS; 1170 } 1171 1172 /** 1173 @brief Get the `CeedVector` of a `CeedOperator` Field 1174 1175 @param[in] op_field `CeedOperator` Field 1176 @param[out] vec Variable to store `CeedVector` 1177 1178 @return An error code: 0 - success, otherwise - failure 1179 1180 @ref Advanced 1181 **/ 1182 int CeedOperatorFieldGetVector(CeedOperatorField op_field, CeedVector *vec) { 1183 *vec = op_field->vec; 1184 return CEED_ERROR_SUCCESS; 1185 } 1186 1187 /** 1188 @brief Get the data of a `CeedOperator` Field. 1189 1190 Any arguments set as `NULL` are ignored. 1191 1192 @param[in] op_field `CeedOperator` Field 1193 @param[out] field_name Variable to store the field name 1194 @param[out] rstr Variable to store `CeedElemRestriction` 1195 @param[out] basis Variable to store `CeedBasis` 1196 @param[out] vec Variable to store `CeedVector` 1197 1198 @return An error code: 0 - success, otherwise - failure 1199 1200 @ref Advanced 1201 **/ 1202 int CeedOperatorFieldGetData(CeedOperatorField op_field, const char **field_name, CeedElemRestriction *rstr, CeedBasis *basis, CeedVector *vec) { 1203 if (field_name) CeedCall(CeedOperatorFieldGetName(op_field, field_name)); 1204 if (rstr) CeedCall(CeedOperatorFieldGetElemRestriction(op_field, rstr)); 1205 if (basis) CeedCall(CeedOperatorFieldGetBasis(op_field, basis)); 1206 if (vec) CeedCall(CeedOperatorFieldGetVector(op_field, vec)); 1207 return CEED_ERROR_SUCCESS; 1208 } 1209 1210 /** 1211 @brief Add a sub-operator to a composite `CeedOperator` 1212 1213 @param[in,out] composite_op Composite `CeedOperator` 1214 @param[in] sub_op Sub-operator `CeedOperator` 1215 1216 @return An error code: 0 - success, otherwise - failure 1217 1218 @ref User 1219 */ 1220 int CeedCompositeOperatorAddSub(CeedOperator composite_op, CeedOperator sub_op) { 1221 bool is_immutable; 1222 Ceed ceed; 1223 1224 CeedCall(CeedOperatorGetCeed(composite_op, &ceed)); 1225 CeedCheck(composite_op->is_composite, ceed, CEED_ERROR_MINOR, "CeedOperator is not a composite operator"); 1226 CeedCheck(composite_op->num_suboperators < CEED_COMPOSITE_MAX, ceed, CEED_ERROR_UNSUPPORTED, "Cannot add additional sub-operators"); 1227 CeedCall(CeedOperatorIsImmutable(composite_op, &is_immutable)); 1228 CeedCheck(!is_immutable, ceed, CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable"); 1229 1230 { 1231 CeedSize input_size, output_size; 1232 1233 CeedCall(CeedOperatorGetActiveVectorLengths(sub_op, &input_size, &output_size)); 1234 if (composite_op->input_size == -1) composite_op->input_size = input_size; 1235 if (composite_op->output_size == -1) composite_op->output_size = output_size; 1236 // Note, a size of -1 means no active vector restriction set, so no incompatibility 1237 CeedCheck((input_size == -1 || input_size == composite_op->input_size) && (output_size == -1 || output_size == composite_op->output_size), ceed, 1238 CEED_ERROR_MAJOR, 1239 "Sub-operators must have compatible dimensions; composite operator of shape (%" CeedSize_FMT ", %" CeedSize_FMT 1240 ") not compatible with sub-operator of " 1241 "shape (%" CeedSize_FMT ", %" CeedSize_FMT ")", 1242 composite_op->input_size, composite_op->output_size, input_size, output_size); 1243 } 1244 1245 composite_op->sub_operators[composite_op->num_suboperators] = sub_op; 1246 CeedCall(CeedOperatorReference(sub_op)); 1247 composite_op->num_suboperators++; 1248 return CEED_ERROR_SUCCESS; 1249 } 1250 1251 /** 1252 @brief Get the number of sub-operators associated with a `CeedOperator` 1253 1254 @param[in] op `CeedOperator` 1255 @param[out] num_suboperators Variable to store number of sub-operators 1256 1257 @return An error code: 0 - success, otherwise - failure 1258 1259 @ref Backend 1260 **/ 1261 int CeedCompositeOperatorGetNumSub(CeedOperator op, CeedInt *num_suboperators) { 1262 bool is_composite; 1263 1264 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1265 CeedCheck(is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Only defined for a composite operator"); 1266 *num_suboperators = op->num_suboperators; 1267 return CEED_ERROR_SUCCESS; 1268 } 1269 1270 /** 1271 @brief Get the list of sub-operators associated with a `CeedOperator` 1272 1273 @param[in] op `CeedOperator` 1274 @param[out] sub_operators Variable to store list of sub-operators 1275 1276 @return An error code: 0 - success, otherwise - failure 1277 1278 @ref Backend 1279 **/ 1280 int CeedCompositeOperatorGetSubList(CeedOperator op, CeedOperator **sub_operators) { 1281 bool is_composite; 1282 1283 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1284 CeedCheck(is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Only defined for a composite operator"); 1285 *sub_operators = op->sub_operators; 1286 return CEED_ERROR_SUCCESS; 1287 } 1288 1289 /** 1290 @brief Check if a `CeedOperator` is ready to be used. 1291 1292 @param[in] op `CeedOperator` to check 1293 1294 @return An error code: 0 - success, otherwise - failure 1295 1296 @ref User 1297 **/ 1298 int CeedOperatorCheckReady(CeedOperator op) { 1299 bool is_at_points, is_composite; 1300 Ceed ceed; 1301 CeedQFunction qf = NULL; 1302 1303 if (op->is_interface_setup) return CEED_ERROR_SUCCESS; 1304 1305 CeedCall(CeedOperatorGetCeed(op, &ceed)); 1306 CeedCall(CeedOperatorIsAtPoints(op, &is_at_points)); 1307 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1308 if (!is_composite) CeedCall(CeedOperatorGetQFunction(op, &qf)); 1309 if (is_composite) { 1310 CeedInt num_suboperators; 1311 1312 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 1313 if (!num_suboperators) { 1314 // Empty operator setup 1315 op->input_size = 0; 1316 op->output_size = 0; 1317 } else { 1318 CeedOperator *sub_operators; 1319 1320 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1321 for (CeedInt i = 0; i < num_suboperators; i++) { 1322 CeedCall(CeedOperatorCheckReady(sub_operators[i])); 1323 } 1324 // Sub-operators could be modified after adding to composite operator 1325 // Need to verify no lvec incompatibility from any changes 1326 CeedSize input_size, output_size; 1327 CeedCall(CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size)); 1328 } 1329 } else { 1330 CeedInt num_input_fields, num_output_fields; 1331 1332 CeedCheck(op->num_fields > 0, ceed, CEED_ERROR_INCOMPLETE, "No operator fields set"); 1333 CeedCall(CeedQFunctionGetFields(qf, &num_input_fields, NULL, &num_output_fields, NULL)); 1334 CeedCheck(op->num_fields == num_input_fields + num_output_fields, ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set"); 1335 CeedCheck(op->has_restriction, ceed, CEED_ERROR_INCOMPLETE, "At least one restriction required"); 1336 CeedCheck(op->num_qpts > 0 || is_at_points, ceed, CEED_ERROR_INCOMPLETE, 1337 "At least one non-collocated CeedBasis is required or the number of quadrature points must be set"); 1338 } 1339 1340 // Flag as immutable and ready 1341 op->is_interface_setup = true; 1342 if (qf && qf != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionSetImmutable(qf)); 1343 if (op->dqf && op->dqf != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionSetImmutable(op->dqf)); 1344 if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionSetImmutable(op->dqfT)); 1345 return CEED_ERROR_SUCCESS; 1346 } 1347 1348 /** 1349 @brief Get vector lengths for the active input and/or output `CeedVector` of a `CeedOperator`. 1350 1351 Note: Lengths of `-1` indicate that the CeedOperator does not have an active input and/or output. 1352 1353 @param[in] op `CeedOperator` 1354 @param[out] input_size Variable to store active input vector length, or `NULL` 1355 @param[out] output_size Variable to store active output vector length, or `NULL` 1356 1357 @return An error code: 0 - success, otherwise - failure 1358 1359 @ref User 1360 **/ 1361 int CeedOperatorGetActiveVectorLengths(CeedOperator op, CeedSize *input_size, CeedSize *output_size) { 1362 bool is_composite; 1363 1364 if (input_size) *input_size = op->input_size; 1365 if (output_size) *output_size = op->output_size; 1366 1367 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1368 if (is_composite && (op->input_size == -1 || op->output_size == -1)) { 1369 CeedInt num_suboperators; 1370 CeedOperator *sub_operators; 1371 1372 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 1373 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1374 for (CeedInt i = 0; i < num_suboperators; i++) { 1375 CeedSize sub_input_size, sub_output_size; 1376 1377 CeedCall(CeedOperatorGetActiveVectorLengths(sub_operators[i], &sub_input_size, &sub_output_size)); 1378 if (op->input_size == -1) op->input_size = sub_input_size; 1379 if (op->output_size == -1) op->output_size = sub_output_size; 1380 // Note, a size of -1 means no active vector restriction set, so no incompatibility 1381 CeedCheck((sub_input_size == -1 || sub_input_size == op->input_size) && (sub_output_size == -1 || sub_output_size == op->output_size), 1382 CeedOperatorReturnCeed(op), CEED_ERROR_MAJOR, 1383 "Sub-operators must have compatible dimensions; composite operator of shape (%" CeedSize_FMT ", %" CeedSize_FMT 1384 ") not compatible with sub-operator of " 1385 "shape (%" CeedSize_FMT ", %" CeedSize_FMT ")", 1386 op->input_size, op->output_size, input_size, output_size); 1387 } 1388 } 1389 return CEED_ERROR_SUCCESS; 1390 } 1391 1392 /** 1393 @brief Set reuse of `CeedQFunction` data in `CeedOperatorLinearAssemble*()` functions. 1394 1395 When `reuse_assembly_data = false` (default), the `CeedQFunction` associated with this `CeedOperator` is re-assembled every time a `CeedOperatorLinearAssemble*()` function is called. 1396 When `reuse_assembly_data = true`, the `CeedQFunction` associated with this `CeedOperator` is reused between calls to @ref CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(). 1397 1398 @param[in] op `CeedOperator` 1399 @param[in] reuse_assembly_data Boolean flag setting assembly data reuse 1400 1401 @return An error code: 0 - success, otherwise - failure 1402 1403 @ref Advanced 1404 **/ 1405 int CeedOperatorSetQFunctionAssemblyReuse(CeedOperator op, bool reuse_assembly_data) { 1406 bool is_composite; 1407 1408 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1409 if (is_composite) { 1410 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1411 CeedCall(CeedOperatorSetQFunctionAssemblyReuse(op->sub_operators[i], reuse_assembly_data)); 1412 } 1413 } else { 1414 CeedCall(CeedQFunctionAssemblyDataSetReuse(op->qf_assembled, reuse_assembly_data)); 1415 } 1416 return CEED_ERROR_SUCCESS; 1417 } 1418 1419 /** 1420 @brief Mark `CeedQFunction` data as updated and the `CeedQFunction` as requiring re-assembly. 1421 1422 @param[in] op `CeedOperator` 1423 @param[in] needs_data_update Boolean flag setting assembly data reuse 1424 1425 @return An error code: 0 - success, otherwise - failure 1426 1427 @ref Advanced 1428 **/ 1429 int CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(CeedOperator op, bool needs_data_update) { 1430 bool is_composite; 1431 1432 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1433 if (is_composite) { 1434 CeedInt num_suboperators; 1435 CeedOperator *sub_operators; 1436 1437 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 1438 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1439 for (CeedInt i = 0; i < num_suboperators; i++) { 1440 CeedCall(CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(sub_operators[i], needs_data_update)); 1441 } 1442 } else { 1443 CeedCall(CeedQFunctionAssemblyDataSetUpdateNeeded(op->qf_assembled, needs_data_update)); 1444 } 1445 return CEED_ERROR_SUCCESS; 1446 } 1447 1448 /** 1449 @brief Set name of `CeedOperator` for @ref CeedOperatorView() output 1450 1451 @param[in,out] op `CeedOperator` 1452 @param[in] name Name to set, or NULL to remove previously set name 1453 1454 @return An error code: 0 - success, otherwise - failure 1455 1456 @ref User 1457 **/ 1458 int CeedOperatorSetName(CeedOperator op, const char *name) { 1459 char *name_copy; 1460 size_t name_len = name ? strlen(name) : 0; 1461 1462 CeedCall(CeedFree(&op->name)); 1463 if (name_len > 0) { 1464 CeedCall(CeedCalloc(name_len + 1, &name_copy)); 1465 memcpy(name_copy, name, name_len); 1466 op->name = name_copy; 1467 } 1468 return CEED_ERROR_SUCCESS; 1469 } 1470 1471 /** 1472 @brief Core logic for viewing a `CeedOperator` 1473 1474 @param[in] op `CeedOperator` to view brief summary 1475 @param[in] stream Stream to write; typically `stdout` or a file 1476 1477 @return Error code: 0 - success, otherwise - failure 1478 1479 @ref User 1480 **/ 1481 int CeedOperatorView_Core(CeedOperator op, FILE *stream, bool is_full) { 1482 bool has_name = op->name, is_composite; 1483 1484 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1485 if (is_composite) { 1486 CeedInt num_suboperators; 1487 CeedOperator *sub_operators; 1488 1489 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 1490 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1491 fprintf(stream, "Composite CeedOperator%s%s\n", has_name ? " - " : "", has_name ? op->name : ""); 1492 1493 for (CeedInt i = 0; i < num_suboperators; i++) { 1494 has_name = sub_operators[i]->name; 1495 fprintf(stream, " SubOperator %" CeedInt_FMT "%s%s%s\n", i, has_name ? " - " : "", has_name ? sub_operators[i]->name : "", is_full ? ":" : ""); 1496 if (is_full) CeedCall(CeedOperatorSingleView(sub_operators[i], 1, stream)); 1497 } 1498 } else { 1499 fprintf(stream, "CeedOperator%s%s\n", has_name ? " - " : "", has_name ? op->name : ""); 1500 if (is_full) CeedCall(CeedOperatorSingleView(op, 0, stream)); 1501 } 1502 return CEED_ERROR_SUCCESS; 1503 } 1504 1505 /** 1506 @brief View a `CeedOperator` 1507 1508 @param[in] op `CeedOperator` to view 1509 @param[in] stream Stream to write; typically `stdout` or a file 1510 1511 @return Error code: 0 - success, otherwise - failure 1512 1513 @ref User 1514 **/ 1515 int CeedOperatorView(CeedOperator op, FILE *stream) { 1516 CeedCall(CeedOperatorView_Core(op, stream, true)); 1517 return CEED_ERROR_SUCCESS; 1518 } 1519 1520 /** 1521 @brief View a brief summary `CeedOperator` 1522 1523 @param[in] op `CeedOperator` to view brief summary 1524 @param[in] stream Stream to write; typically `stdout` or a file 1525 1526 @return Error code: 0 - success, otherwise - failure 1527 1528 @ref User 1529 **/ 1530 int CeedOperatorViewTerse(CeedOperator op, FILE *stream) { 1531 CeedCall(CeedOperatorView_Core(op, stream, false)); 1532 return CEED_ERROR_SUCCESS; 1533 } 1534 1535 /** 1536 @brief Get the `Ceed` associated with a `CeedOperator` 1537 1538 @param[in] op `CeedOperator` 1539 @param[out] ceed Variable to store `Ceed` 1540 1541 @return An error code: 0 - success, otherwise - failure 1542 1543 @ref Advanced 1544 **/ 1545 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) { 1546 *ceed = CeedOperatorReturnCeed(op); 1547 return CEED_ERROR_SUCCESS; 1548 } 1549 1550 /** 1551 @brief Return the `Ceed` associated with a `CeedOperator` 1552 1553 @param[in] op `CeedOperator` 1554 1555 @return `Ceed` associated with the `op` 1556 1557 @ref Advanced 1558 **/ 1559 Ceed CeedOperatorReturnCeed(CeedOperator op) { return op->ceed; } 1560 1561 /** 1562 @brief Get the number of elements associated with a `CeedOperator` 1563 1564 @param[in] op `CeedOperator` 1565 @param[out] num_elem Variable to store number of elements 1566 1567 @return An error code: 0 - success, otherwise - failure 1568 1569 @ref Advanced 1570 **/ 1571 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) { 1572 bool is_composite; 1573 1574 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1575 CeedCheck(!is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Not defined for composite operator"); 1576 *num_elem = op->num_elem; 1577 return CEED_ERROR_SUCCESS; 1578 } 1579 1580 /** 1581 @brief Get the number of quadrature points associated with a `CeedOperator` 1582 1583 @param[in] op `CeedOperator` 1584 @param[out] num_qpts Variable to store vector number of quadrature points 1585 1586 @return An error code: 0 - success, otherwise - failure 1587 1588 @ref Advanced 1589 **/ 1590 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) { 1591 bool is_composite; 1592 1593 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1594 CeedCheck(!is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Not defined for composite operator"); 1595 *num_qpts = op->num_qpts; 1596 return CEED_ERROR_SUCCESS; 1597 } 1598 1599 /** 1600 @brief Estimate number of FLOPs required to apply `CeedOperator` on the active `CeedVector` 1601 1602 @param[in] op `CeedOperator` to estimate FLOPs for 1603 @param[out] flops Address of variable to hold FLOPs estimate 1604 1605 @ref Backend 1606 **/ 1607 int CeedOperatorGetFlopsEstimate(CeedOperator op, CeedSize *flops) { 1608 bool is_composite; 1609 1610 CeedCall(CeedOperatorCheckReady(op)); 1611 1612 *flops = 0; 1613 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1614 if (is_composite) { 1615 CeedInt num_suboperators; 1616 1617 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 1618 CeedOperator *sub_operators; 1619 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1620 1621 // FLOPs for each suboperator 1622 for (CeedInt i = 0; i < num_suboperators; i++) { 1623 CeedSize suboperator_flops; 1624 1625 CeedCall(CeedOperatorGetFlopsEstimate(sub_operators[i], &suboperator_flops)); 1626 *flops += suboperator_flops; 1627 } 1628 } else { 1629 CeedInt num_input_fields, num_output_fields, num_elem = 0; 1630 CeedQFunction qf; 1631 CeedQFunctionField *qf_input_fields, *qf_output_fields; 1632 CeedOperatorField *op_input_fields, *op_output_fields; 1633 1634 CeedCall(CeedOperatorGetQFunction(op, &qf)); 1635 CeedCall(CeedQFunctionGetFields(qf, &num_input_fields, &qf_input_fields, &num_output_fields, &qf_output_fields)); 1636 CeedCall(CeedOperatorGetFields(op, NULL, &op_input_fields, NULL, &op_output_fields)); 1637 CeedCall(CeedOperatorGetNumElements(op, &num_elem)); 1638 1639 // Input FLOPs 1640 for (CeedInt i = 0; i < num_input_fields; i++) { 1641 CeedVector vec; 1642 1643 CeedCall(CeedOperatorFieldGetVector(op_input_fields[i], &vec)); 1644 if (vec == CEED_VECTOR_ACTIVE) { 1645 CeedEvalMode eval_mode; 1646 CeedSize rstr_flops, basis_flops; 1647 CeedElemRestriction rstr; 1648 CeedBasis basis; 1649 1650 CeedCall(CeedOperatorFieldGetElemRestriction(op_input_fields[i], &rstr)); 1651 CeedCall(CeedElemRestrictionGetFlopsEstimate(rstr, CEED_NOTRANSPOSE, &rstr_flops)); 1652 *flops += rstr_flops; 1653 CeedCall(CeedOperatorFieldGetBasis(op_input_fields[i], &basis)); 1654 CeedCall(CeedQFunctionFieldGetEvalMode(qf_input_fields[i], &eval_mode)); 1655 CeedCall(CeedBasisGetFlopsEstimate(basis, CEED_NOTRANSPOSE, eval_mode, &basis_flops)); 1656 *flops += basis_flops * num_elem; 1657 } 1658 } 1659 // QF FLOPs 1660 { 1661 CeedInt num_qpts; 1662 CeedSize qf_flops; 1663 CeedQFunction qf; 1664 1665 CeedCall(CeedOperatorGetNumQuadraturePoints(op, &num_qpts)); 1666 CeedCall(CeedOperatorGetQFunction(op, &qf)); 1667 CeedCall(CeedQFunctionGetFlopsEstimate(qf, &qf_flops)); 1668 CeedCheck(qf_flops > -1, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPLETE, 1669 "Must set CeedQFunction FLOPs estimate with CeedQFunctionSetUserFlopsEstimate"); 1670 *flops += num_elem * num_qpts * qf_flops; 1671 } 1672 1673 // Output FLOPs 1674 for (CeedInt i = 0; i < num_output_fields; i++) { 1675 CeedVector vec; 1676 1677 CeedCall(CeedOperatorFieldGetVector(op_output_fields[i], &vec)); 1678 if (vec == CEED_VECTOR_ACTIVE) { 1679 CeedEvalMode eval_mode; 1680 CeedSize rstr_flops, basis_flops; 1681 CeedElemRestriction rstr; 1682 CeedBasis basis; 1683 1684 CeedCall(CeedOperatorFieldGetElemRestriction(op_output_fields[i], &rstr)); 1685 CeedCall(CeedElemRestrictionGetFlopsEstimate(rstr, CEED_TRANSPOSE, &rstr_flops)); 1686 *flops += rstr_flops; 1687 CeedCall(CeedOperatorFieldGetBasis(op_output_fields[i], &basis)); 1688 CeedCall(CeedQFunctionFieldGetEvalMode(qf_output_fields[i], &eval_mode)); 1689 CeedCall(CeedBasisGetFlopsEstimate(basis, CEED_TRANSPOSE, eval_mode, &basis_flops)); 1690 *flops += basis_flops * num_elem; 1691 } 1692 } 1693 } 1694 return CEED_ERROR_SUCCESS; 1695 } 1696 1697 /** 1698 @brief Get `CeedQFunction` global context for a `CeedOperator`. 1699 1700 The caller is responsible for destroying `ctx` returned from this function via @ref CeedQFunctionContextDestroy(). 1701 1702 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`. 1703 This `CeedQFunctionContext` will be destroyed if `ctx` is the only reference to this `CeedQFunctionContext`. 1704 1705 @param[in] op `CeedOperator` 1706 @param[out] ctx Variable to store `CeedQFunctionContext` 1707 1708 @return An error code: 0 - success, otherwise - failure 1709 1710 @ref Advanced 1711 **/ 1712 int CeedOperatorGetContext(CeedOperator op, CeedQFunctionContext *ctx) { 1713 bool is_composite; 1714 CeedQFunction qf; 1715 CeedQFunctionContext qf_ctx; 1716 1717 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1718 CeedCheck(!is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPATIBLE, "Cannot retrieve CeedQFunctionContext for composite operator"); 1719 CeedCall(CeedOperatorGetQFunction(op, &qf)); 1720 CeedCall(CeedQFunctionGetInnerContext(qf, &qf_ctx)); 1721 if (qf_ctx) CeedCall(CeedQFunctionContextReferenceCopy(qf_ctx, ctx)); 1722 return CEED_ERROR_SUCCESS; 1723 } 1724 1725 /** 1726 @brief Get label for a registered `CeedQFunctionContext` field, or `NULL` if no field has been registered with this `field_name`. 1727 1728 Fields are registered via `CeedQFunctionContextRegister*()` functions (eg. @ref CeedQFunctionContextRegisterDouble()). 1729 1730 @param[in] op `CeedOperator` 1731 @param[in] field_name Name of field to retrieve label 1732 @param[out] field_label Variable to field label 1733 1734 @return An error code: 0 - success, otherwise - failure 1735 1736 @ref User 1737 **/ 1738 int CeedOperatorGetContextFieldLabel(CeedOperator op, const char *field_name, CeedContextFieldLabel *field_label) { 1739 bool is_composite, field_found = false; 1740 1741 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1742 1743 if (is_composite) { 1744 // Composite operator 1745 // -- Check if composite label already created 1746 for (CeedInt i = 0; i < op->num_context_labels; i++) { 1747 if (!strcmp(op->context_labels[i]->name, field_name)) { 1748 *field_label = op->context_labels[i]; 1749 return CEED_ERROR_SUCCESS; 1750 } 1751 } 1752 1753 // -- Create composite label if needed 1754 CeedInt num_sub; 1755 CeedOperator *sub_operators; 1756 CeedContextFieldLabel new_field_label; 1757 1758 CeedCall(CeedCalloc(1, &new_field_label)); 1759 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_sub)); 1760 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1761 CeedCall(CeedCalloc(num_sub, &new_field_label->sub_labels)); 1762 new_field_label->num_sub_labels = num_sub; 1763 1764 for (CeedInt i = 0; i < num_sub; i++) { 1765 if (sub_operators[i]->qf->ctx) { 1766 CeedContextFieldLabel new_field_label_i; 1767 1768 CeedCall(CeedQFunctionContextGetFieldLabel(sub_operators[i]->qf->ctx, field_name, &new_field_label_i)); 1769 if (new_field_label_i) { 1770 field_found = true; 1771 new_field_label->sub_labels[i] = new_field_label_i; 1772 new_field_label->name = new_field_label_i->name; 1773 new_field_label->description = new_field_label_i->description; 1774 if (new_field_label->type && new_field_label->type != new_field_label_i->type) { 1775 // LCOV_EXCL_START 1776 CeedCall(CeedFree(&new_field_label)); 1777 return CeedError(CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPATIBLE, "Incompatible field types on sub-operator contexts. %s != %s", 1778 CeedContextFieldTypes[new_field_label->type], CeedContextFieldTypes[new_field_label_i->type]); 1779 // LCOV_EXCL_STOP 1780 } else { 1781 new_field_label->type = new_field_label_i->type; 1782 } 1783 if (new_field_label->num_values != 0 && new_field_label->num_values != new_field_label_i->num_values) { 1784 // LCOV_EXCL_START 1785 CeedCall(CeedFree(&new_field_label)); 1786 return CeedError(CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPATIBLE, 1787 "Incompatible field number of values on sub-operator contexts. %zu != %zu", new_field_label->num_values, 1788 new_field_label_i->num_values); 1789 // LCOV_EXCL_STOP 1790 } else { 1791 new_field_label->num_values = new_field_label_i->num_values; 1792 } 1793 } 1794 } 1795 } 1796 // -- Cleanup if field was found 1797 if (field_found) { 1798 *field_label = new_field_label; 1799 } else { 1800 // LCOV_EXCL_START 1801 CeedCall(CeedFree(&new_field_label->sub_labels)); 1802 CeedCall(CeedFree(&new_field_label)); 1803 *field_label = NULL; 1804 // LCOV_EXCL_STOP 1805 } 1806 } else { 1807 CeedQFunction qf; 1808 CeedQFunctionContext ctx; 1809 1810 // Single, non-composite operator 1811 CeedCall(CeedOperatorGetQFunction(op, &qf)); 1812 CeedCall(CeedQFunctionGetInnerContext(qf, &ctx)); 1813 if (ctx) { 1814 CeedCall(CeedQFunctionContextGetFieldLabel(ctx, field_name, field_label)); 1815 } else { 1816 *field_label = NULL; 1817 } 1818 } 1819 1820 // Set label in operator 1821 if (*field_label) { 1822 (*field_label)->from_op = true; 1823 1824 // Move new composite label to operator 1825 if (op->num_context_labels == 0) { 1826 CeedCall(CeedCalloc(1, &op->context_labels)); 1827 op->max_context_labels = 1; 1828 } else if (op->num_context_labels == op->max_context_labels) { 1829 CeedCall(CeedRealloc(2 * op->num_context_labels, &op->context_labels)); 1830 op->max_context_labels *= 2; 1831 } 1832 op->context_labels[op->num_context_labels] = *field_label; 1833 op->num_context_labels++; 1834 } 1835 return CEED_ERROR_SUCCESS; 1836 } 1837 1838 /** 1839 @brief Set `CeedQFunctionContext` field holding double precision values. 1840 1841 For composite operators, the values are set in all sub-operator `CeedQFunctionContext` that have a matching `field_name`. 1842 1843 @param[in,out] op `CeedOperator` 1844 @param[in] field_label Label of field to set 1845 @param[in] values Values to set 1846 1847 @return An error code: 0 - success, otherwise - failure 1848 1849 @ref User 1850 **/ 1851 int CeedOperatorSetContextDouble(CeedOperator op, CeedContextFieldLabel field_label, double *values) { 1852 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, values); 1853 } 1854 1855 /** 1856 @brief Get `CeedQFunctionContext` field holding double precision values, read-only. 1857 1858 For composite operators, the values correspond to the first sub-operator `CeedQFunctionContext` that has a matching `field_name`. 1859 1860 @param[in] op `CeedOperator` 1861 @param[in] field_label Label of field to get 1862 @param[out] num_values Number of values in the field label 1863 @param[out] values Pointer to context values 1864 1865 @return An error code: 0 - success, otherwise - failure 1866 1867 @ref User 1868 **/ 1869 int CeedOperatorGetContextDoubleRead(CeedOperator op, CeedContextFieldLabel field_label, size_t *num_values, const double **values) { 1870 return CeedOperatorContextGetGenericRead(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, num_values, values); 1871 } 1872 1873 /** 1874 @brief Restore `CeedQFunctionContext` field holding double precision values, read-only. 1875 1876 @param[in] op `CeedOperator` 1877 @param[in] field_label Label of field to restore 1878 @param[out] values Pointer to context values 1879 1880 @return An error code: 0 - success, otherwise - failure 1881 1882 @ref User 1883 **/ 1884 int CeedOperatorRestoreContextDoubleRead(CeedOperator op, CeedContextFieldLabel field_label, const double **values) { 1885 return CeedOperatorContextRestoreGenericRead(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, values); 1886 } 1887 1888 /** 1889 @brief Set `CeedQFunctionContext` field holding `int32` values. 1890 1891 For composite operators, the values are set in all sub-operator `CeedQFunctionContext` that have a matching `field_name`. 1892 1893 @param[in,out] op `CeedOperator` 1894 @param[in] field_label Label of field to set 1895 @param[in] values Values to set 1896 1897 @return An error code: 0 - success, otherwise - failure 1898 1899 @ref User 1900 **/ 1901 int CeedOperatorSetContextInt32(CeedOperator op, CeedContextFieldLabel field_label, int32_t *values) { 1902 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_INT32, values); 1903 } 1904 1905 /** 1906 @brief Get `CeedQFunctionContext` field holding `int32` values, read-only. 1907 1908 For composite operators, the values correspond to the first sub-operator `CeedQFunctionContext` that has a matching `field_name`. 1909 1910 @param[in] op `CeedOperator` 1911 @param[in] field_label Label of field to get 1912 @param[out] num_values Number of `int32` values in `values` 1913 @param[out] values Pointer to context values 1914 1915 @return An error code: 0 - success, otherwise - failure 1916 1917 @ref User 1918 **/ 1919 int CeedOperatorGetContextInt32Read(CeedOperator op, CeedContextFieldLabel field_label, size_t *num_values, const int32_t **values) { 1920 return CeedOperatorContextGetGenericRead(op, field_label, CEED_CONTEXT_FIELD_INT32, num_values, values); 1921 } 1922 1923 /** 1924 @brief Restore `CeedQFunctionContext` field holding `int32` values, read-only. 1925 1926 @param[in] op `CeedOperator` 1927 @param[in] field_label Label of field to get 1928 @param[out] values Pointer to context values 1929 1930 @return An error code: 0 - success, otherwise - failure 1931 1932 @ref User 1933 **/ 1934 int CeedOperatorRestoreContextInt32Read(CeedOperator op, CeedContextFieldLabel field_label, const int32_t **values) { 1935 return CeedOperatorContextRestoreGenericRead(op, field_label, CEED_CONTEXT_FIELD_INT32, values); 1936 } 1937 1938 /** 1939 @brief Set `CeedQFunctionContext` field holding boolean values. 1940 1941 For composite operators, the values are set in all sub-operator `CeedQFunctionContext` that have a matching `field_name`. 1942 1943 @param[in,out] op `CeedOperator` 1944 @param[in] field_label Label of field to set 1945 @param[in] values Values to set 1946 1947 @return An error code: 0 - success, otherwise - failure 1948 1949 @ref User 1950 **/ 1951 int CeedOperatorSetContextBoolean(CeedOperator op, CeedContextFieldLabel field_label, bool *values) { 1952 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_BOOL, values); 1953 } 1954 1955 /** 1956 @brief Get `CeedQFunctionContext` field holding boolean values, read-only. 1957 1958 For composite operators, the values correspond to the first sub-operator `CeedQFunctionContext` that has a matching `field_name`. 1959 1960 @param[in] op `CeedOperator` 1961 @param[in] field_label Label of field to get 1962 @param[out] num_values Number of boolean values in `values` 1963 @param[out] values Pointer to context values 1964 1965 @return An error code: 0 - success, otherwise - failure 1966 1967 @ref User 1968 **/ 1969 int CeedOperatorGetContextBooleanRead(CeedOperator op, CeedContextFieldLabel field_label, size_t *num_values, const bool **values) { 1970 return CeedOperatorContextGetGenericRead(op, field_label, CEED_CONTEXT_FIELD_BOOL, num_values, values); 1971 } 1972 1973 /** 1974 @brief Restore `CeedQFunctionContext` field holding boolean values, read-only. 1975 1976 @param[in] op `CeedOperator` 1977 @param[in] field_label Label of field to get 1978 @param[out] values Pointer to context values 1979 1980 @return An error code: 0 - success, otherwise - failure 1981 1982 @ref User 1983 **/ 1984 int CeedOperatorRestoreContextBooleanRead(CeedOperator op, CeedContextFieldLabel field_label, const bool **values) { 1985 return CeedOperatorContextRestoreGenericRead(op, field_label, CEED_CONTEXT_FIELD_BOOL, values); 1986 } 1987 1988 /** 1989 @brief Apply `CeedOperator` to a `CeedVector`. 1990 1991 This computes the action of the operator on the specified (active) input, yielding its (active) output. 1992 All inputs and outputs must be specified using @ref CeedOperatorSetField(). 1993 1994 Note: Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable. 1995 1996 @param[in] op `CeedOperator` to apply 1997 @param[in] in `CeedVector` containing input state or @ref CEED_VECTOR_NONE if there are no active inputs 1998 @param[out] out `CeedVector` to store result of applying operator (must be distinct from `in`) or @ref CEED_VECTOR_NONE if there are no active outputs 1999 @param[in] request Address of @ref CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE 2000 2001 @return An error code: 0 - success, otherwise - failure 2002 2003 @ref User 2004 **/ 2005 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, CeedRequest *request) { 2006 bool is_composite; 2007 2008 CeedCall(CeedOperatorCheckReady(op)); 2009 2010 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 2011 if (is_composite) { 2012 // Composite Operator 2013 if (op->ApplyComposite) { 2014 CeedCall(op->ApplyComposite(op, in, out, request)); 2015 } else { 2016 CeedInt num_suboperators; 2017 CeedOperator *sub_operators; 2018 2019 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 2020 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 2021 2022 // Zero all output vectors 2023 if (out != CEED_VECTOR_NONE) CeedCall(CeedVectorSetValue(out, 0.0)); 2024 for (CeedInt i = 0; i < num_suboperators; i++) { 2025 CeedInt num_output_fields; 2026 CeedOperatorField *output_fields; 2027 2028 CeedCall(CeedOperatorGetFields(sub_operators[i], NULL, NULL, &num_output_fields, &output_fields)); 2029 for (CeedInt j = 0; j < num_output_fields; j++) { 2030 CeedVector vec; 2031 2032 CeedCall(CeedOperatorFieldGetVector(output_fields[j], &vec)); 2033 if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) { 2034 CeedCall(CeedVectorSetValue(vec, 0.0)); 2035 } 2036 } 2037 } 2038 // Apply 2039 for (CeedInt i = 0; i < num_suboperators; i++) { 2040 CeedCall(CeedOperatorApplyAdd(sub_operators[i], in, out, request)); 2041 } 2042 } 2043 } else { 2044 // Standard Operator 2045 if (op->Apply) { 2046 CeedCall(op->Apply(op, in, out, request)); 2047 } else { 2048 CeedInt num_output_fields; 2049 CeedOperatorField *output_fields; 2050 2051 CeedCall(CeedOperatorGetFields(op, NULL, NULL, &num_output_fields, &output_fields)); 2052 // Zero all output vectors 2053 for (CeedInt i = 0; i < num_output_fields; i++) { 2054 CeedVector vec; 2055 2056 CeedCall(CeedOperatorFieldGetVector(output_fields[i], &vec)); 2057 if (vec == CEED_VECTOR_ACTIVE) vec = out; 2058 if (vec != CEED_VECTOR_NONE) CeedCall(CeedVectorSetValue(vec, 0.0)); 2059 } 2060 // Apply 2061 if (op->num_elem > 0) CeedCall(op->ApplyAdd(op, in, out, request)); 2062 } 2063 } 2064 return CEED_ERROR_SUCCESS; 2065 } 2066 2067 /** 2068 @brief Apply `CeedOperator` to a `CeedVector` and add result to output `CeedVector`. 2069 2070 This computes the action of the operator on the specified (active) input, yielding its (active) output. 2071 All inputs and outputs must be specified using @ref CeedOperatorSetField(). 2072 2073 @param[in] op `CeedOperator` to apply 2074 @param[in] in `CeedVector` containing input state or @ref CEED_VECTOR_NONE if there are no active inputs 2075 @param[out] out `CeedVector` to sum in result of applying operator (must be distinct from `in`) or @ref CEED_VECTOR_NONE if there are no active outputs 2076 @param[in] request Address of @ref CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE 2077 2078 @return An error code: 0 - success, otherwise - failure 2079 2080 @ref User 2081 **/ 2082 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, CeedRequest *request) { 2083 bool is_composite; 2084 2085 CeedCall(CeedOperatorCheckReady(op)); 2086 2087 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 2088 if (is_composite) { 2089 // Composite Operator 2090 if (op->ApplyAddComposite) { 2091 CeedCall(op->ApplyAddComposite(op, in, out, request)); 2092 } else { 2093 CeedInt num_suboperators; 2094 CeedOperator *sub_operators; 2095 2096 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 2097 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 2098 for (CeedInt i = 0; i < num_suboperators; i++) { 2099 CeedCall(CeedOperatorApplyAdd(sub_operators[i], in, out, request)); 2100 } 2101 } 2102 } else if (op->num_elem > 0) { 2103 // Standard Operator 2104 CeedCall(op->ApplyAdd(op, in, out, request)); 2105 } 2106 return CEED_ERROR_SUCCESS; 2107 } 2108 2109 /** 2110 @brief Destroy a `CeedOperator` 2111 2112 @param[in,out] op `CeedOperator` to destroy 2113 2114 @return An error code: 0 - success, otherwise - failure 2115 2116 @ref User 2117 **/ 2118 int CeedOperatorDestroy(CeedOperator *op) { 2119 if (!*op || --(*op)->ref_count > 0) { 2120 *op = NULL; 2121 return CEED_ERROR_SUCCESS; 2122 } 2123 if ((*op)->Destroy) CeedCall((*op)->Destroy(*op)); 2124 CeedCall(CeedDestroy(&(*op)->ceed)); 2125 // Free fields 2126 for (CeedInt i = 0; i < (*op)->num_fields; i++) { 2127 if ((*op)->input_fields[i]) { 2128 if ((*op)->input_fields[i]->elem_rstr != CEED_ELEMRESTRICTION_NONE) { 2129 CeedCall(CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_rstr)); 2130 } 2131 if ((*op)->input_fields[i]->basis != CEED_BASIS_NONE) { 2132 CeedCall(CeedBasisDestroy(&(*op)->input_fields[i]->basis)); 2133 } 2134 if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE && (*op)->input_fields[i]->vec != CEED_VECTOR_NONE) { 2135 CeedCall(CeedVectorDestroy(&(*op)->input_fields[i]->vec)); 2136 } 2137 CeedCall(CeedFree(&(*op)->input_fields[i]->field_name)); 2138 CeedCall(CeedFree(&(*op)->input_fields[i])); 2139 } 2140 } 2141 for (CeedInt i = 0; i < (*op)->num_fields; i++) { 2142 if ((*op)->output_fields[i]) { 2143 CeedCall(CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_rstr)); 2144 if ((*op)->output_fields[i]->basis != CEED_BASIS_NONE) { 2145 CeedCall(CeedBasisDestroy(&(*op)->output_fields[i]->basis)); 2146 } 2147 if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE && (*op)->output_fields[i]->vec != CEED_VECTOR_NONE) { 2148 CeedCall(CeedVectorDestroy(&(*op)->output_fields[i]->vec)); 2149 } 2150 CeedCall(CeedFree(&(*op)->output_fields[i]->field_name)); 2151 CeedCall(CeedFree(&(*op)->output_fields[i])); 2152 } 2153 } 2154 // AtPoints data 2155 CeedCall(CeedVectorDestroy(&(*op)->point_coords)); 2156 CeedCall(CeedElemRestrictionDestroy(&(*op)->rstr_points)); 2157 CeedCall(CeedElemRestrictionDestroy(&(*op)->first_points_rstr)); 2158 // Destroy sub_operators 2159 for (CeedInt i = 0; i < (*op)->num_suboperators; i++) { 2160 if ((*op)->sub_operators[i]) { 2161 CeedCall(CeedOperatorDestroy(&(*op)->sub_operators[i])); 2162 } 2163 } 2164 CeedCall(CeedQFunctionDestroy(&(*op)->qf)); 2165 CeedCall(CeedQFunctionDestroy(&(*op)->dqf)); 2166 CeedCall(CeedQFunctionDestroy(&(*op)->dqfT)); 2167 // Destroy any composite labels 2168 if ((*op)->is_composite) { 2169 for (CeedInt i = 0; i < (*op)->num_context_labels; i++) { 2170 CeedCall(CeedFree(&(*op)->context_labels[i]->sub_labels)); 2171 CeedCall(CeedFree(&(*op)->context_labels[i])); 2172 } 2173 } 2174 CeedCall(CeedFree(&(*op)->context_labels)); 2175 2176 // Destroy fallback 2177 CeedCall(CeedOperatorDestroy(&(*op)->op_fallback)); 2178 2179 // Destroy assembly data 2180 CeedCall(CeedQFunctionAssemblyDataDestroy(&(*op)->qf_assembled)); 2181 CeedCall(CeedOperatorAssemblyDataDestroy(&(*op)->op_assembled)); 2182 2183 CeedCall(CeedFree(&(*op)->input_fields)); 2184 CeedCall(CeedFree(&(*op)->output_fields)); 2185 CeedCall(CeedFree(&(*op)->sub_operators)); 2186 CeedCall(CeedFree(&(*op)->name)); 2187 CeedCall(CeedFree(op)); 2188 return CEED_ERROR_SUCCESS; 2189 } 2190 2191 /// @} 2192