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(CeedCalloc(CEED_FIELD_MAX, &(*op)->input_fields)); 746 CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*op)->output_fields)); 747 CeedCall(ceed->OperatorCreate(*op)); 748 return CEED_ERROR_SUCCESS; 749 } 750 751 /** 752 @brief Create a `CeedOperator` for evaluation at evaluation at arbitrary points in each element. 753 754 A `CeedBasis` and `CeedElemRestriction` can be associated with `CeedQFunction` fields with `CeedOperator` SetField. 755 The locations of each point are set with @ref CeedOperatorAtPointsSetPoints(). 756 757 @param[in] ceed `Ceed` object used to create the `CeedOperator` 758 @param[in] qf `CeedQFunction` defining the action of the operator at quadrature points 759 @param[in] dqf `CeedQFunction` defining the action of the Jacobian of @a qf (or @ref CEED_QFUNCTION_NONE) 760 @param[in] dqfT `CeedQFunction` defining the action of the transpose of the Jacobian of @a qf (or @ref CEED_QFUNCTION_NONE) 761 @param[out] op Address of the variable where the newly created CeedOperator will be stored 762 763 @return An error code: 0 - success, otherwise - failure 764 765 @ref User 766 */ 767 int CeedOperatorCreateAtPoints(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, CeedQFunction dqfT, CeedOperator *op) { 768 if (!ceed->OperatorCreateAtPoints) { 769 Ceed delegate; 770 771 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Operator")); 772 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedOperatorCreateAtPoints"); 773 CeedCall(CeedOperatorCreateAtPoints(delegate, qf, dqf, dqfT, op)); 774 return CEED_ERROR_SUCCESS; 775 } 776 777 CeedCheck(qf && qf != CEED_QFUNCTION_NONE, ceed, CEED_ERROR_MINOR, "Operator must have a valid CeedQFunction."); 778 779 CeedCall(CeedCalloc(1, op)); 780 CeedCall(CeedReferenceCopy(ceed, &(*op)->ceed)); 781 (*op)->ref_count = 1; 782 (*op)->is_at_points = true; 783 (*op)->input_size = -1; 784 (*op)->output_size = -1; 785 CeedCall(CeedQFunctionReferenceCopy(qf, &(*op)->qf)); 786 if (dqf && dqf != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionReferenceCopy(dqf, &(*op)->dqf)); 787 if (dqfT && dqfT != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionReferenceCopy(dqfT, &(*op)->dqfT)); 788 CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*op)->input_fields)); 789 CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*op)->output_fields)); 790 CeedCall(ceed->OperatorCreateAtPoints(*op)); 791 return CEED_ERROR_SUCCESS; 792 } 793 794 /** 795 @brief Create a composite `CeedOperator` that composes the action of several `CeedOperator` 796 797 @param[in] ceed `Ceed` object used to create the `CeedOperator` 798 @param[out] op Address of the variable where the newly created composite `CeedOperator` will be stored 799 800 @return An error code: 0 - success, otherwise - failure 801 802 @ref User 803 */ 804 int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) { 805 if (!ceed->CompositeOperatorCreate) { 806 Ceed delegate; 807 808 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Operator")); 809 if (delegate) { 810 CeedCall(CeedCompositeOperatorCreate(delegate, op)); 811 return CEED_ERROR_SUCCESS; 812 } 813 } 814 815 CeedCall(CeedCalloc(1, op)); 816 CeedCall(CeedReferenceCopy(ceed, &(*op)->ceed)); 817 (*op)->ref_count = 1; 818 (*op)->is_composite = true; 819 CeedCall(CeedCalloc(CEED_COMPOSITE_MAX, &(*op)->sub_operators)); 820 (*op)->input_size = -1; 821 (*op)->output_size = -1; 822 823 if (ceed->CompositeOperatorCreate) CeedCall(ceed->CompositeOperatorCreate(*op)); 824 return CEED_ERROR_SUCCESS; 825 } 826 827 /** 828 @brief Copy the pointer to a `CeedOperator`. 829 830 Both pointers should be destroyed with @ref CeedOperatorDestroy(). 831 832 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`. 833 This `CeedOperator` will be destroyed if `*op_copy` is the only reference to this `CeedOperator`. 834 835 @param[in] op `CeedOperator` to copy reference to 836 @param[in,out] op_copy Variable to store copied reference 837 838 @return An error code: 0 - success, otherwise - failure 839 840 @ref User 841 **/ 842 int CeedOperatorReferenceCopy(CeedOperator op, CeedOperator *op_copy) { 843 CeedCall(CeedOperatorReference(op)); 844 CeedCall(CeedOperatorDestroy(op_copy)); 845 *op_copy = op; 846 return CEED_ERROR_SUCCESS; 847 } 848 849 /** 850 @brief Provide a field to a `CeedOperator` for use by its `CeedQFunction`. 851 852 This function is used to specify both active and passive fields to a `CeedOperator`. 853 For passive fields, a `CeedVector` `vec` must be provided. 854 Passive fields can inputs or outputs (updated in-place when operator is applied). 855 856 Active fields must be specified using this function, but their data (in a `CeedVector`) is passed in @ref CeedOperatorApply(). 857 There can be at most one active input `CeedVector` and at most one active output@ref CeedVector passed to @ref CeedOperatorApply(). 858 859 The number of quadrature points must agree across all points. 860 When using @ref CEED_BASIS_NONE, the number of quadrature points is determined by the element size of `rstr`. 861 862 @param[in,out] op `CeedOperator` on which to provide the field 863 @param[in] field_name Name of the field (to be matched with the name used by `CeedQFunction`) 864 @param[in] rstr `CeedElemRestriction` 865 @param[in] basis `CeedBasis` in which the field resides or @ref CEED_BASIS_NONE if collocated with quadrature points 866 @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` 867 868 @return An error code: 0 - success, otherwise - failure 869 870 @ref User 871 **/ 872 int CeedOperatorSetField(CeedOperator op, const char *field_name, CeedElemRestriction rstr, CeedBasis basis, CeedVector vec) { 873 bool is_input = true, is_at_points, is_composite, is_immutable; 874 CeedInt num_elem = 0, num_qpts = 0, num_input_fields, num_output_fields; 875 Ceed ceed; 876 CeedQFunction qf; 877 CeedQFunctionField qf_field, *qf_input_fields, *qf_output_fields; 878 CeedOperatorField *op_field; 879 880 CeedCall(CeedOperatorGetCeed(op, &ceed)); 881 CeedCall(CeedOperatorIsAtPoints(op, &is_at_points)); 882 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 883 CeedCall(CeedOperatorIsImmutable(op, &is_immutable)); 884 CeedCheck(!is_composite, ceed, CEED_ERROR_INCOMPATIBLE, "Cannot add field to composite operator."); 885 CeedCheck(!is_immutable, ceed, CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable"); 886 CeedCheck(rstr, ceed, CEED_ERROR_INCOMPATIBLE, "CeedElemRestriction rstr for field \"%s\" must be non-NULL.", field_name); 887 CeedCheck(basis, ceed, CEED_ERROR_INCOMPATIBLE, "CeedBasis basis for field \"%s\" must be non-NULL.", field_name); 888 CeedCheck(vec, ceed, CEED_ERROR_INCOMPATIBLE, "CeedVector vec for field \"%s\" must be non-NULL.", field_name); 889 890 CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem)); 891 CeedCheck(rstr == CEED_ELEMRESTRICTION_NONE || !op->has_restriction || num_elem == op->num_elem, ceed, CEED_ERROR_DIMENSION, 892 "CeedElemRestriction with %" CeedInt_FMT " elements incompatible with prior %" CeedInt_FMT " elements", num_elem, op->num_elem); 893 { 894 CeedRestrictionType rstr_type; 895 896 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 897 if (rstr_type == CEED_RESTRICTION_POINTS) { 898 CeedCheck(is_at_points, ceed, CEED_ERROR_UNSUPPORTED, "CeedElemRestriction AtPoints not supported for standard operator fields"); 899 CeedCheck(basis == CEED_BASIS_NONE, ceed, CEED_ERROR_UNSUPPORTED, "CeedElemRestriction AtPoints must be used with CEED_BASIS_NONE"); 900 if (!op->first_points_rstr) { 901 CeedCall(CeedElemRestrictionReferenceCopy(rstr, &op->first_points_rstr)); 902 } else { 903 bool are_compatible; 904 905 CeedCall(CeedElemRestrictionAtPointsAreCompatible(op->first_points_rstr, rstr, &are_compatible)); 906 CeedCheck(are_compatible, ceed, CEED_ERROR_INCOMPATIBLE, 907 "CeedElemRestriction must have compatible offsets with previously set CeedElemRestriction"); 908 } 909 } 910 } 911 912 if (basis == CEED_BASIS_NONE) CeedCall(CeedElemRestrictionGetElementSize(rstr, &num_qpts)); 913 else CeedCall(CeedBasisGetNumQuadraturePoints(basis, &num_qpts)); 914 CeedCheck(op->num_qpts == 0 || num_qpts == op->num_qpts, ceed, CEED_ERROR_DIMENSION, 915 "%s must correspond to the same number of quadrature points as previously added CeedBases. Found %" CeedInt_FMT 916 " quadrature points but expected %" CeedInt_FMT " quadrature points.", 917 basis == CEED_BASIS_NONE ? "CeedElemRestriction" : "CeedBasis", num_qpts, op->num_qpts); 918 919 CeedCall(CeedOperatorGetQFunction(op, &qf)); 920 CeedCall(CeedQFunctionGetFields(qf, &num_input_fields, &qf_input_fields, &num_output_fields, &qf_output_fields)); 921 for (CeedInt i = 0; i < num_input_fields; i++) { 922 const char *qf_field_name; 923 924 CeedCall(CeedQFunctionFieldGetName(qf_input_fields[i], &qf_field_name)); 925 if (!strcmp(field_name, qf_field_name)) { 926 qf_field = qf_input_fields[i]; 927 op_field = &op->input_fields[i]; 928 goto found; 929 } 930 } 931 is_input = false; 932 for (CeedInt i = 0; i < num_output_fields; i++) { 933 const char *qf_field_name; 934 935 CeedCall(CeedQFunctionFieldGetName(qf_output_fields[i], &qf_field_name)); 936 if (!strcmp(field_name, qf_field_name)) { 937 qf_field = qf_output_fields[i]; 938 op_field = &op->output_fields[i]; 939 goto found; 940 } 941 } 942 // LCOV_EXCL_START 943 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "CeedQFunction has no knowledge of field '%s'", field_name); 944 // LCOV_EXCL_STOP 945 found: 946 CeedCall(CeedOperatorCheckField(ceed, qf_field, rstr, basis)); 947 CeedCall(CeedCalloc(1, op_field)); 948 949 if (vec == CEED_VECTOR_ACTIVE) { 950 CeedSize l_size; 951 952 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &l_size)); 953 if (is_input) { 954 if (op->input_size == -1) op->input_size = l_size; 955 CeedCheck(l_size == op->input_size, ceed, CEED_ERROR_INCOMPATIBLE, 956 "LVector size %" CeedSize_FMT " does not match previous size %" CeedSize_FMT "", l_size, op->input_size); 957 } else { 958 if (op->output_size == -1) op->output_size = l_size; 959 CeedCheck(l_size == op->output_size, ceed, CEED_ERROR_INCOMPATIBLE, 960 "LVector size %" CeedSize_FMT " does not match previous size %" CeedSize_FMT "", l_size, op->output_size); 961 } 962 } 963 964 CeedCall(CeedVectorReferenceCopy(vec, &(*op_field)->vec)); 965 CeedCall(CeedElemRestrictionReferenceCopy(rstr, &(*op_field)->elem_rstr)); 966 if (rstr != CEED_ELEMRESTRICTION_NONE && !op->has_restriction) { 967 op->num_elem = num_elem; 968 op->has_restriction = true; // Restriction set, but num_elem may be 0 969 } 970 CeedCall(CeedBasisReferenceCopy(basis, &(*op_field)->basis)); 971 if (op->num_qpts == 0 && !is_at_points) op->num_qpts = num_qpts; // no consistent number of qpts for OperatorAtPoints 972 op->num_fields += 1; 973 CeedCall(CeedStringAllocCopy(field_name, (char **)&(*op_field)->field_name)); 974 return CEED_ERROR_SUCCESS; 975 } 976 977 /** 978 @brief Get the `CeedOperator` Field of a `CeedOperator`. 979 980 Note: Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable. 981 982 @param[in] op `CeedOperator` 983 @param[out] num_input_fields Variable to store number of input fields 984 @param[out] input_fields Variable to store input fields 985 @param[out] num_output_fields Variable to store number of output fields 986 @param[out] output_fields Variable to store output fields 987 988 @return An error code: 0 - success, otherwise - failure 989 990 @ref Advanced 991 **/ 992 int CeedOperatorGetFields(CeedOperator op, CeedInt *num_input_fields, CeedOperatorField **input_fields, CeedInt *num_output_fields, 993 CeedOperatorField **output_fields) { 994 bool is_composite; 995 CeedQFunction qf; 996 997 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 998 CeedCheck(!is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Not defined for composite operator"); 999 CeedCall(CeedOperatorCheckReady(op)); 1000 1001 CeedCall(CeedOperatorGetQFunction(op, &qf)); 1002 CeedCall(CeedQFunctionGetFields(qf, num_input_fields, NULL, num_output_fields, NULL)); 1003 if (input_fields) *input_fields = op->input_fields; 1004 if (output_fields) *output_fields = op->output_fields; 1005 return CEED_ERROR_SUCCESS; 1006 } 1007 1008 /** 1009 @brief Set the arbitrary points in each element for a `CeedOperator` at points. 1010 1011 Note: Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable. 1012 1013 @param[in,out] op `CeedOperator` at points 1014 @param[in] rstr_points `CeedElemRestriction` for the coordinates of each point by element 1015 @param[in] point_coords `CeedVector` holding coordinates of each point 1016 1017 @return An error code: 0 - success, otherwise - failure 1018 1019 @ref Advanced 1020 **/ 1021 int CeedOperatorAtPointsSetPoints(CeedOperator op, CeedElemRestriction rstr_points, CeedVector point_coords) { 1022 bool is_at_points, is_immutable; 1023 Ceed ceed; 1024 1025 CeedCall(CeedOperatorGetCeed(op, &ceed)); 1026 CeedCall(CeedOperatorIsAtPoints(op, &is_at_points)); 1027 CeedCall(CeedOperatorIsImmutable(op, &is_immutable)); 1028 CeedCheck(is_at_points, ceed, CEED_ERROR_MINOR, "Only defined for operator at points"); 1029 CeedCheck(!is_immutable, ceed, CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable"); 1030 1031 if (!op->first_points_rstr) { 1032 CeedCall(CeedElemRestrictionReferenceCopy(rstr_points, &op->first_points_rstr)); 1033 } else { 1034 bool are_compatible; 1035 1036 CeedCall(CeedElemRestrictionAtPointsAreCompatible(op->first_points_rstr, rstr_points, &are_compatible)); 1037 CeedCheck(are_compatible, ceed, CEED_ERROR_INCOMPATIBLE, 1038 "CeedElemRestriction must have compatible offsets with previously set field CeedElemRestriction"); 1039 } 1040 1041 CeedCall(CeedElemRestrictionReferenceCopy(rstr_points, &op->rstr_points)); 1042 CeedCall(CeedVectorReferenceCopy(point_coords, &op->point_coords)); 1043 return CEED_ERROR_SUCCESS; 1044 } 1045 1046 /** 1047 @brief Get a boolean value indicating if the `CeedOperator` was created with `CeedOperatorCreateAtPoints` 1048 1049 @param[in] op `CeedOperator` 1050 @param[out] is_at_points Variable to store at points status 1051 1052 @return An error code: 0 - success, otherwise - failure 1053 1054 @ref User 1055 **/ 1056 int CeedOperatorIsAtPoints(CeedOperator op, bool *is_at_points) { 1057 *is_at_points = op->is_at_points; 1058 return CEED_ERROR_SUCCESS; 1059 } 1060 1061 /** 1062 @brief Get the arbitrary points in each element for a `CeedOperator` at points. 1063 1064 Note: Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable. 1065 1066 @param[in] op `CeedOperator` at points 1067 @param[out] rstr_points Variable to hold `CeedElemRestriction` for the coordinates of each point by element 1068 @param[out] point_coords Variable to hold `CeedVector` holding coordinates of each point 1069 1070 @return An error code: 0 - success, otherwise - failure 1071 1072 @ref Advanced 1073 **/ 1074 int CeedOperatorAtPointsGetPoints(CeedOperator op, CeedElemRestriction *rstr_points, CeedVector *point_coords) { 1075 bool is_at_points; 1076 1077 CeedCall(CeedOperatorIsAtPoints(op, &is_at_points)); 1078 CeedCheck(is_at_points, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Only defined for operator at points"); 1079 CeedCall(CeedOperatorCheckReady(op)); 1080 1081 if (rstr_points) CeedCall(CeedElemRestrictionReferenceCopy(op->rstr_points, rstr_points)); 1082 if (point_coords) CeedCall(CeedVectorReferenceCopy(op->point_coords, point_coords)); 1083 return CEED_ERROR_SUCCESS; 1084 } 1085 1086 /** 1087 @brief Get a `CeedOperator` Field of a `CeedOperator` from its name. 1088 1089 `op_field` is set to `NULL` if the field is not found. 1090 1091 Note: Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable. 1092 1093 @param[in] op `CeedOperator` 1094 @param[in] field_name Name of desired `CeedOperator` Field 1095 @param[out] op_field `CeedOperator` Field corresponding to the name 1096 1097 @return An error code: 0 - success, otherwise - failure 1098 1099 @ref Advanced 1100 **/ 1101 int CeedOperatorGetFieldByName(CeedOperator op, const char *field_name, CeedOperatorField *op_field) { 1102 const char *name; 1103 CeedInt num_input_fields, num_output_fields; 1104 CeedOperatorField *input_fields, *output_fields; 1105 1106 *op_field = NULL; 1107 CeedCall(CeedOperatorGetFields(op, &num_input_fields, &input_fields, &num_output_fields, &output_fields)); 1108 for (CeedInt i = 0; i < num_input_fields; i++) { 1109 CeedCall(CeedOperatorFieldGetName(input_fields[i], &name)); 1110 if (!strcmp(name, field_name)) { 1111 *op_field = input_fields[i]; 1112 return CEED_ERROR_SUCCESS; 1113 } 1114 } 1115 for (CeedInt i = 0; i < num_output_fields; i++) { 1116 CeedCall(CeedOperatorFieldGetName(output_fields[i], &name)); 1117 if (!strcmp(name, field_name)) { 1118 *op_field = output_fields[i]; 1119 return CEED_ERROR_SUCCESS; 1120 } 1121 } 1122 return CEED_ERROR_SUCCESS; 1123 } 1124 1125 /** 1126 @brief Get the name of a `CeedOperator` Field 1127 1128 @param[in] op_field `CeedOperator` Field 1129 @param[out] field_name Variable to store the field name 1130 1131 @return An error code: 0 - success, otherwise - failure 1132 1133 @ref Advanced 1134 **/ 1135 int CeedOperatorFieldGetName(CeedOperatorField op_field, const char **field_name) { 1136 *field_name = op_field->field_name; 1137 return CEED_ERROR_SUCCESS; 1138 } 1139 1140 /** 1141 @brief Get the `CeedElemRestriction` of a `CeedOperator` Field 1142 1143 @param[in] op_field `CeedOperator` Field 1144 @param[out] rstr Variable to store `CeedElemRestriction` 1145 1146 @return An error code: 0 - success, otherwise - failure 1147 1148 @ref Advanced 1149 **/ 1150 int CeedOperatorFieldGetElemRestriction(CeedOperatorField op_field, CeedElemRestriction *rstr) { 1151 *rstr = op_field->elem_rstr; 1152 return CEED_ERROR_SUCCESS; 1153 } 1154 1155 /** 1156 @brief Get the `CeedBasis` of a `CeedOperator` Field 1157 1158 @param[in] op_field `CeedOperator` Field 1159 @param[out] basis Variable to store `CeedBasis` 1160 1161 @return An error code: 0 - success, otherwise - failure 1162 1163 @ref Advanced 1164 **/ 1165 int CeedOperatorFieldGetBasis(CeedOperatorField op_field, CeedBasis *basis) { 1166 *basis = op_field->basis; 1167 return CEED_ERROR_SUCCESS; 1168 } 1169 1170 /** 1171 @brief Get the `CeedVector` of a `CeedOperator` Field 1172 1173 @param[in] op_field `CeedOperator` Field 1174 @param[out] vec Variable to store `CeedVector` 1175 1176 @return An error code: 0 - success, otherwise - failure 1177 1178 @ref Advanced 1179 **/ 1180 int CeedOperatorFieldGetVector(CeedOperatorField op_field, CeedVector *vec) { 1181 *vec = op_field->vec; 1182 return CEED_ERROR_SUCCESS; 1183 } 1184 1185 /** 1186 @brief Get the data of a `CeedOperator` Field. 1187 1188 Any arguments set as `NULL` are ignored. 1189 1190 @param[in] op_field `CeedOperator` Field 1191 @param[out] field_name Variable to store the field name 1192 @param[out] rstr Variable to store `CeedElemRestriction` 1193 @param[out] basis Variable to store `CeedBasis` 1194 @param[out] vec Variable to store `CeedVector` 1195 1196 @return An error code: 0 - success, otherwise - failure 1197 1198 @ref Advanced 1199 **/ 1200 int CeedOperatorFieldGetData(CeedOperatorField op_field, const char **field_name, CeedElemRestriction *rstr, CeedBasis *basis, CeedVector *vec) { 1201 if (field_name) CeedCall(CeedOperatorFieldGetName(op_field, field_name)); 1202 if (rstr) CeedCall(CeedOperatorFieldGetElemRestriction(op_field, rstr)); 1203 if (basis) CeedCall(CeedOperatorFieldGetBasis(op_field, basis)); 1204 if (vec) CeedCall(CeedOperatorFieldGetVector(op_field, vec)); 1205 return CEED_ERROR_SUCCESS; 1206 } 1207 1208 /** 1209 @brief Add a sub-operator to a composite `CeedOperator` 1210 1211 @param[in,out] composite_op Composite `CeedOperator` 1212 @param[in] sub_op Sub-operator `CeedOperator` 1213 1214 @return An error code: 0 - success, otherwise - failure 1215 1216 @ref User 1217 */ 1218 int CeedCompositeOperatorAddSub(CeedOperator composite_op, CeedOperator sub_op) { 1219 bool is_immutable; 1220 Ceed ceed; 1221 1222 CeedCall(CeedOperatorGetCeed(composite_op, &ceed)); 1223 CeedCheck(composite_op->is_composite, ceed, CEED_ERROR_MINOR, "CeedOperator is not a composite operator"); 1224 CeedCheck(composite_op->num_suboperators < CEED_COMPOSITE_MAX, ceed, CEED_ERROR_UNSUPPORTED, "Cannot add additional sub-operators"); 1225 CeedCall(CeedOperatorIsImmutable(composite_op, &is_immutable)); 1226 CeedCheck(!is_immutable, ceed, CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable"); 1227 1228 { 1229 CeedSize input_size, output_size; 1230 1231 CeedCall(CeedOperatorGetActiveVectorLengths(sub_op, &input_size, &output_size)); 1232 if (composite_op->input_size == -1) composite_op->input_size = input_size; 1233 if (composite_op->output_size == -1) composite_op->output_size = output_size; 1234 // Note, a size of -1 means no active vector restriction set, so no incompatibility 1235 CeedCheck((input_size == -1 || input_size == composite_op->input_size) && (output_size == -1 || output_size == composite_op->output_size), ceed, 1236 CEED_ERROR_MAJOR, 1237 "Sub-operators must have compatible dimensions; composite operator of shape (%" CeedSize_FMT ", %" CeedSize_FMT 1238 ") not compatible with sub-operator of " 1239 "shape (%" CeedSize_FMT ", %" CeedSize_FMT ")", 1240 composite_op->input_size, composite_op->output_size, input_size, output_size); 1241 } 1242 1243 composite_op->sub_operators[composite_op->num_suboperators] = sub_op; 1244 CeedCall(CeedOperatorReference(sub_op)); 1245 composite_op->num_suboperators++; 1246 return CEED_ERROR_SUCCESS; 1247 } 1248 1249 /** 1250 @brief Get the number of sub-operators associated with a `CeedOperator` 1251 1252 @param[in] op `CeedOperator` 1253 @param[out] num_suboperators Variable to store number of sub-operators 1254 1255 @return An error code: 0 - success, otherwise - failure 1256 1257 @ref Backend 1258 **/ 1259 int CeedCompositeOperatorGetNumSub(CeedOperator op, CeedInt *num_suboperators) { 1260 bool is_composite; 1261 1262 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1263 CeedCheck(is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Only defined for a composite operator"); 1264 *num_suboperators = op->num_suboperators; 1265 return CEED_ERROR_SUCCESS; 1266 } 1267 1268 /** 1269 @brief Get the list of sub-operators associated with a `CeedOperator` 1270 1271 @param[in] op `CeedOperator` 1272 @param[out] sub_operators Variable to store list of sub-operators 1273 1274 @return An error code: 0 - success, otherwise - failure 1275 1276 @ref Backend 1277 **/ 1278 int CeedCompositeOperatorGetSubList(CeedOperator op, CeedOperator **sub_operators) { 1279 bool is_composite; 1280 1281 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1282 CeedCheck(is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Only defined for a composite operator"); 1283 *sub_operators = op->sub_operators; 1284 return CEED_ERROR_SUCCESS; 1285 } 1286 1287 /** 1288 @brief Check if a `CeedOperator` is ready to be used. 1289 1290 @param[in] op `CeedOperator` to check 1291 1292 @return An error code: 0 - success, otherwise - failure 1293 1294 @ref User 1295 **/ 1296 int CeedOperatorCheckReady(CeedOperator op) { 1297 bool is_at_points, is_composite; 1298 Ceed ceed; 1299 CeedQFunction qf = NULL; 1300 1301 if (op->is_interface_setup) return CEED_ERROR_SUCCESS; 1302 1303 CeedCall(CeedOperatorGetCeed(op, &ceed)); 1304 CeedCall(CeedOperatorIsAtPoints(op, &is_at_points)); 1305 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1306 if (!is_composite) CeedCall(CeedOperatorGetQFunction(op, &qf)); 1307 if (is_composite) { 1308 CeedInt num_suboperators; 1309 1310 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 1311 if (!num_suboperators) { 1312 // Empty operator setup 1313 op->input_size = 0; 1314 op->output_size = 0; 1315 } else { 1316 CeedOperator *sub_operators; 1317 1318 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1319 for (CeedInt i = 0; i < num_suboperators; i++) { 1320 CeedCall(CeedOperatorCheckReady(sub_operators[i])); 1321 } 1322 // Sub-operators could be modified after adding to composite operator 1323 // Need to verify no lvec incompatibility from any changes 1324 CeedSize input_size, output_size; 1325 CeedCall(CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size)); 1326 } 1327 } else { 1328 CeedInt num_input_fields, num_output_fields; 1329 1330 CeedCheck(op->num_fields > 0, ceed, CEED_ERROR_INCOMPLETE, "No operator fields set"); 1331 CeedCall(CeedQFunctionGetFields(qf, &num_input_fields, NULL, &num_output_fields, NULL)); 1332 CeedCheck(op->num_fields == num_input_fields + num_output_fields, ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set"); 1333 CeedCheck(op->has_restriction, ceed, CEED_ERROR_INCOMPLETE, "At least one restriction required"); 1334 CeedCheck(op->num_qpts > 0 || is_at_points, ceed, CEED_ERROR_INCOMPLETE, 1335 "At least one non-collocated CeedBasis is required or the number of quadrature points must be set"); 1336 } 1337 1338 // Flag as immutable and ready 1339 op->is_interface_setup = true; 1340 if (qf && qf != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionSetImmutable(qf)); 1341 if (op->dqf && op->dqf != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionSetImmutable(op->dqf)); 1342 if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionSetImmutable(op->dqfT)); 1343 return CEED_ERROR_SUCCESS; 1344 } 1345 1346 /** 1347 @brief Get vector lengths for the active input and/or output `CeedVector` of a `CeedOperator`. 1348 1349 Note: Lengths of `-1` indicate that the CeedOperator does not have an active input and/or output. 1350 1351 @param[in] op `CeedOperator` 1352 @param[out] input_size Variable to store active input vector length, or `NULL` 1353 @param[out] output_size Variable to store active output vector length, or `NULL` 1354 1355 @return An error code: 0 - success, otherwise - failure 1356 1357 @ref User 1358 **/ 1359 int CeedOperatorGetActiveVectorLengths(CeedOperator op, CeedSize *input_size, CeedSize *output_size) { 1360 bool is_composite; 1361 1362 if (input_size) *input_size = op->input_size; 1363 if (output_size) *output_size = op->output_size; 1364 1365 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1366 if (is_composite && (op->input_size == -1 || op->output_size == -1)) { 1367 CeedInt num_suboperators; 1368 CeedOperator *sub_operators; 1369 1370 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 1371 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1372 for (CeedInt i = 0; i < num_suboperators; i++) { 1373 CeedSize sub_input_size, sub_output_size; 1374 1375 CeedCall(CeedOperatorGetActiveVectorLengths(sub_operators[i], &sub_input_size, &sub_output_size)); 1376 if (op->input_size == -1) op->input_size = sub_input_size; 1377 if (op->output_size == -1) op->output_size = sub_output_size; 1378 // Note, a size of -1 means no active vector restriction set, so no incompatibility 1379 CeedCheck((sub_input_size == -1 || sub_input_size == op->input_size) && (sub_output_size == -1 || sub_output_size == op->output_size), 1380 CeedOperatorReturnCeed(op), CEED_ERROR_MAJOR, 1381 "Sub-operators must have compatible dimensions; composite operator of shape (%" CeedSize_FMT ", %" CeedSize_FMT 1382 ") not compatible with sub-operator of " 1383 "shape (%" CeedSize_FMT ", %" CeedSize_FMT ")", 1384 op->input_size, op->output_size, input_size, output_size); 1385 } 1386 } 1387 return CEED_ERROR_SUCCESS; 1388 } 1389 1390 /** 1391 @brief Set reuse of `CeedQFunction` data in `CeedOperatorLinearAssemble*()` functions. 1392 1393 When `reuse_assembly_data = false` (default), the `CeedQFunction` associated with this `CeedOperator` is re-assembled every time a `CeedOperatorLinearAssemble*()` function is called. 1394 When `reuse_assembly_data = true`, the `CeedQFunction` associated with this `CeedOperator` is reused between calls to @ref CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(). 1395 1396 @param[in] op `CeedOperator` 1397 @param[in] reuse_assembly_data Boolean flag setting assembly data reuse 1398 1399 @return An error code: 0 - success, otherwise - failure 1400 1401 @ref Advanced 1402 **/ 1403 int CeedOperatorSetQFunctionAssemblyReuse(CeedOperator op, bool reuse_assembly_data) { 1404 bool is_composite; 1405 1406 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1407 if (is_composite) { 1408 for (CeedInt i = 0; i < op->num_suboperators; i++) { 1409 CeedCall(CeedOperatorSetQFunctionAssemblyReuse(op->sub_operators[i], reuse_assembly_data)); 1410 } 1411 } else { 1412 CeedQFunctionAssemblyData data; 1413 1414 CeedCall(CeedOperatorGetQFunctionAssemblyData(op, &data)); 1415 CeedCall(CeedQFunctionAssemblyDataSetReuse(data, reuse_assembly_data)); 1416 } 1417 return CEED_ERROR_SUCCESS; 1418 } 1419 1420 /** 1421 @brief Mark `CeedQFunction` data as updated and the `CeedQFunction` as requiring re-assembly. 1422 1423 @param[in] op `CeedOperator` 1424 @param[in] needs_data_update Boolean flag setting assembly data reuse 1425 1426 @return An error code: 0 - success, otherwise - failure 1427 1428 @ref Advanced 1429 **/ 1430 int CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(CeedOperator op, bool needs_data_update) { 1431 bool is_composite; 1432 1433 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1434 if (is_composite) { 1435 CeedInt num_suboperators; 1436 CeedOperator *sub_operators; 1437 1438 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 1439 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1440 for (CeedInt i = 0; i < num_suboperators; i++) { 1441 CeedCall(CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(sub_operators[i], needs_data_update)); 1442 } 1443 } else { 1444 CeedQFunctionAssemblyData data; 1445 1446 CeedCall(CeedOperatorGetQFunctionAssemblyData(op, &data)); 1447 CeedCall(CeedQFunctionAssemblyDataSetUpdateNeeded(data, needs_data_update)); 1448 } 1449 return CEED_ERROR_SUCCESS; 1450 } 1451 1452 /** 1453 @brief Set name of `CeedOperator` for @ref CeedOperatorView() output 1454 1455 @param[in,out] op `CeedOperator` 1456 @param[in] name Name to set, or NULL to remove previously set name 1457 1458 @return An error code: 0 - success, otherwise - failure 1459 1460 @ref User 1461 **/ 1462 int CeedOperatorSetName(CeedOperator op, const char *name) { 1463 char *name_copy; 1464 size_t name_len = name ? strlen(name) : 0; 1465 1466 CeedCall(CeedFree(&op->name)); 1467 if (name_len > 0) { 1468 CeedCall(CeedCalloc(name_len + 1, &name_copy)); 1469 memcpy(name_copy, name, name_len); 1470 op->name = name_copy; 1471 } 1472 return CEED_ERROR_SUCCESS; 1473 } 1474 1475 /** 1476 @brief Core logic for viewing a `CeedOperator` 1477 1478 @param[in] op `CeedOperator` to view brief summary 1479 @param[in] stream Stream to write; typically `stdout` or a file 1480 @param[in] is_full Whether to write full operator view or terse 1481 1482 @return Error code: 0 - success, otherwise - failure 1483 **/ 1484 static int CeedOperatorView_Core(CeedOperator op, FILE *stream, bool is_full) { 1485 bool has_name = op->name, is_composite; 1486 1487 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1488 if (is_composite) { 1489 CeedInt num_suboperators; 1490 CeedOperator *sub_operators; 1491 1492 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 1493 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1494 fprintf(stream, "Composite CeedOperator%s%s\n", has_name ? " - " : "", has_name ? op->name : ""); 1495 1496 for (CeedInt i = 0; i < num_suboperators; i++) { 1497 has_name = sub_operators[i]->name; 1498 fprintf(stream, " SubOperator %" CeedInt_FMT "%s%s%s\n", i, has_name ? " - " : "", has_name ? sub_operators[i]->name : "", is_full ? ":" : ""); 1499 if (is_full) CeedCall(CeedOperatorSingleView(sub_operators[i], 1, stream)); 1500 } 1501 } else { 1502 fprintf(stream, "CeedOperator%s%s\n", has_name ? " - " : "", has_name ? op->name : ""); 1503 if (is_full) CeedCall(CeedOperatorSingleView(op, 0, stream)); 1504 } 1505 return CEED_ERROR_SUCCESS; 1506 } 1507 1508 /** 1509 @brief View a `CeedOperator` 1510 1511 @param[in] op `CeedOperator` to view 1512 @param[in] stream Stream to write; typically `stdout` or a file 1513 1514 @return Error code: 0 - success, otherwise - failure 1515 1516 @ref User 1517 **/ 1518 int CeedOperatorView(CeedOperator op, FILE *stream) { 1519 CeedCall(CeedOperatorView_Core(op, stream, true)); 1520 return CEED_ERROR_SUCCESS; 1521 } 1522 1523 /** 1524 @brief View a brief summary `CeedOperator` 1525 1526 @param[in] op `CeedOperator` to view brief summary 1527 @param[in] stream Stream to write; typically `stdout` or a file 1528 1529 @return Error code: 0 - success, otherwise - failure 1530 1531 @ref User 1532 **/ 1533 int CeedOperatorViewTerse(CeedOperator op, FILE *stream) { 1534 CeedCall(CeedOperatorView_Core(op, stream, false)); 1535 return CEED_ERROR_SUCCESS; 1536 } 1537 1538 /** 1539 @brief Get the `Ceed` associated with a `CeedOperator` 1540 1541 @param[in] op `CeedOperator` 1542 @param[out] ceed Variable to store `Ceed` 1543 1544 @return An error code: 0 - success, otherwise - failure 1545 1546 @ref Advanced 1547 **/ 1548 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) { 1549 *ceed = CeedOperatorReturnCeed(op); 1550 return CEED_ERROR_SUCCESS; 1551 } 1552 1553 /** 1554 @brief Return the `Ceed` associated with a `CeedOperator` 1555 1556 @param[in] op `CeedOperator` 1557 1558 @return `Ceed` associated with the `op` 1559 1560 @ref Advanced 1561 **/ 1562 Ceed CeedOperatorReturnCeed(CeedOperator op) { return op->ceed; } 1563 1564 /** 1565 @brief Get the number of elements associated with a `CeedOperator` 1566 1567 @param[in] op `CeedOperator` 1568 @param[out] num_elem Variable to store number of elements 1569 1570 @return An error code: 0 - success, otherwise - failure 1571 1572 @ref Advanced 1573 **/ 1574 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) { 1575 bool is_composite; 1576 1577 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1578 CeedCheck(!is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Not defined for composite operator"); 1579 *num_elem = op->num_elem; 1580 return CEED_ERROR_SUCCESS; 1581 } 1582 1583 /** 1584 @brief Get the number of quadrature points associated with a `CeedOperator` 1585 1586 @param[in] op `CeedOperator` 1587 @param[out] num_qpts Variable to store vector number of quadrature points 1588 1589 @return An error code: 0 - success, otherwise - failure 1590 1591 @ref Advanced 1592 **/ 1593 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) { 1594 bool is_composite; 1595 1596 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1597 CeedCheck(!is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Not defined for composite operator"); 1598 *num_qpts = op->num_qpts; 1599 return CEED_ERROR_SUCCESS; 1600 } 1601 1602 /** 1603 @brief Estimate number of FLOPs required to apply `CeedOperator` on the active `CeedVector` 1604 1605 @param[in] op `CeedOperator` to estimate FLOPs for 1606 @param[out] flops Address of variable to hold FLOPs estimate 1607 1608 @ref Backend 1609 **/ 1610 int CeedOperatorGetFlopsEstimate(CeedOperator op, CeedSize *flops) { 1611 bool is_composite; 1612 1613 CeedCall(CeedOperatorCheckReady(op)); 1614 1615 *flops = 0; 1616 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1617 if (is_composite) { 1618 CeedInt num_suboperators; 1619 1620 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 1621 CeedOperator *sub_operators; 1622 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1623 1624 // FLOPs for each suboperator 1625 for (CeedInt i = 0; i < num_suboperators; i++) { 1626 CeedSize suboperator_flops; 1627 1628 CeedCall(CeedOperatorGetFlopsEstimate(sub_operators[i], &suboperator_flops)); 1629 *flops += suboperator_flops; 1630 } 1631 } else { 1632 CeedInt num_input_fields, num_output_fields, num_elem = 0; 1633 CeedQFunction qf; 1634 CeedQFunctionField *qf_input_fields, *qf_output_fields; 1635 CeedOperatorField *op_input_fields, *op_output_fields; 1636 1637 CeedCall(CeedOperatorGetQFunction(op, &qf)); 1638 CeedCall(CeedQFunctionGetFields(qf, &num_input_fields, &qf_input_fields, &num_output_fields, &qf_output_fields)); 1639 CeedCall(CeedOperatorGetFields(op, NULL, &op_input_fields, NULL, &op_output_fields)); 1640 CeedCall(CeedOperatorGetNumElements(op, &num_elem)); 1641 1642 // Input FLOPs 1643 for (CeedInt i = 0; i < num_input_fields; i++) { 1644 CeedVector vec; 1645 1646 CeedCall(CeedOperatorFieldGetVector(op_input_fields[i], &vec)); 1647 if (vec == CEED_VECTOR_ACTIVE) { 1648 CeedEvalMode eval_mode; 1649 CeedSize rstr_flops, basis_flops; 1650 CeedElemRestriction rstr; 1651 CeedBasis basis; 1652 1653 CeedCall(CeedOperatorFieldGetElemRestriction(op_input_fields[i], &rstr)); 1654 CeedCall(CeedElemRestrictionGetFlopsEstimate(rstr, CEED_NOTRANSPOSE, &rstr_flops)); 1655 *flops += rstr_flops; 1656 CeedCall(CeedOperatorFieldGetBasis(op_input_fields[i], &basis)); 1657 CeedCall(CeedQFunctionFieldGetEvalMode(qf_input_fields[i], &eval_mode)); 1658 CeedCall(CeedBasisGetFlopsEstimate(basis, CEED_NOTRANSPOSE, eval_mode, &basis_flops)); 1659 *flops += basis_flops * num_elem; 1660 } 1661 } 1662 // QF FLOPs 1663 { 1664 CeedInt num_qpts; 1665 CeedSize qf_flops; 1666 CeedQFunction qf; 1667 1668 CeedCall(CeedOperatorGetNumQuadraturePoints(op, &num_qpts)); 1669 CeedCall(CeedOperatorGetQFunction(op, &qf)); 1670 CeedCall(CeedQFunctionGetFlopsEstimate(qf, &qf_flops)); 1671 CeedCheck(qf_flops > -1, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPLETE, 1672 "Must set CeedQFunction FLOPs estimate with CeedQFunctionSetUserFlopsEstimate"); 1673 *flops += num_elem * num_qpts * qf_flops; 1674 } 1675 1676 // Output FLOPs 1677 for (CeedInt i = 0; i < num_output_fields; i++) { 1678 CeedVector vec; 1679 1680 CeedCall(CeedOperatorFieldGetVector(op_output_fields[i], &vec)); 1681 if (vec == CEED_VECTOR_ACTIVE) { 1682 CeedEvalMode eval_mode; 1683 CeedSize rstr_flops, basis_flops; 1684 CeedElemRestriction rstr; 1685 CeedBasis basis; 1686 1687 CeedCall(CeedOperatorFieldGetElemRestriction(op_output_fields[i], &rstr)); 1688 CeedCall(CeedElemRestrictionGetFlopsEstimate(rstr, CEED_TRANSPOSE, &rstr_flops)); 1689 *flops += rstr_flops; 1690 CeedCall(CeedOperatorFieldGetBasis(op_output_fields[i], &basis)); 1691 CeedCall(CeedQFunctionFieldGetEvalMode(qf_output_fields[i], &eval_mode)); 1692 CeedCall(CeedBasisGetFlopsEstimate(basis, CEED_TRANSPOSE, eval_mode, &basis_flops)); 1693 *flops += basis_flops * num_elem; 1694 } 1695 } 1696 } 1697 return CEED_ERROR_SUCCESS; 1698 } 1699 1700 /** 1701 @brief Get `CeedQFunction` global context for a `CeedOperator`. 1702 1703 The caller is responsible for destroying `ctx` returned from this function via @ref CeedQFunctionContextDestroy(). 1704 1705 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`. 1706 This `CeedQFunctionContext` will be destroyed if `ctx` is the only reference to this `CeedQFunctionContext`. 1707 1708 @param[in] op `CeedOperator` 1709 @param[out] ctx Variable to store `CeedQFunctionContext` 1710 1711 @return An error code: 0 - success, otherwise - failure 1712 1713 @ref Advanced 1714 **/ 1715 int CeedOperatorGetContext(CeedOperator op, CeedQFunctionContext *ctx) { 1716 bool is_composite; 1717 CeedQFunction qf; 1718 CeedQFunctionContext qf_ctx; 1719 1720 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1721 CeedCheck(!is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPATIBLE, "Cannot retrieve CeedQFunctionContext for composite operator"); 1722 CeedCall(CeedOperatorGetQFunction(op, &qf)); 1723 CeedCall(CeedQFunctionGetInnerContext(qf, &qf_ctx)); 1724 if (qf_ctx) CeedCall(CeedQFunctionContextReferenceCopy(qf_ctx, ctx)); 1725 return CEED_ERROR_SUCCESS; 1726 } 1727 1728 /** 1729 @brief Get label for a registered `CeedQFunctionContext` field, or `NULL` if no field has been registered with this `field_name`. 1730 1731 Fields are registered via `CeedQFunctionContextRegister*()` functions (eg. @ref CeedQFunctionContextRegisterDouble()). 1732 1733 @param[in] op `CeedOperator` 1734 @param[in] field_name Name of field to retrieve label 1735 @param[out] field_label Variable to field label 1736 1737 @return An error code: 0 - success, otherwise - failure 1738 1739 @ref User 1740 **/ 1741 int CeedOperatorGetContextFieldLabel(CeedOperator op, const char *field_name, CeedContextFieldLabel *field_label) { 1742 bool is_composite, field_found = false; 1743 1744 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 1745 1746 if (is_composite) { 1747 // Composite operator 1748 // -- Check if composite label already created 1749 for (CeedInt i = 0; i < op->num_context_labels; i++) { 1750 if (!strcmp(op->context_labels[i]->name, field_name)) { 1751 *field_label = op->context_labels[i]; 1752 return CEED_ERROR_SUCCESS; 1753 } 1754 } 1755 1756 // -- Create composite label if needed 1757 CeedInt num_sub; 1758 CeedOperator *sub_operators; 1759 CeedContextFieldLabel new_field_label; 1760 1761 CeedCall(CeedCalloc(1, &new_field_label)); 1762 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_sub)); 1763 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 1764 CeedCall(CeedCalloc(num_sub, &new_field_label->sub_labels)); 1765 new_field_label->num_sub_labels = num_sub; 1766 1767 for (CeedInt i = 0; i < num_sub; i++) { 1768 if (sub_operators[i]->qf->ctx) { 1769 CeedContextFieldLabel new_field_label_i; 1770 1771 CeedCall(CeedQFunctionContextGetFieldLabel(sub_operators[i]->qf->ctx, field_name, &new_field_label_i)); 1772 if (new_field_label_i) { 1773 field_found = true; 1774 new_field_label->sub_labels[i] = new_field_label_i; 1775 new_field_label->name = new_field_label_i->name; 1776 new_field_label->description = new_field_label_i->description; 1777 if (new_field_label->type && new_field_label->type != new_field_label_i->type) { 1778 // LCOV_EXCL_START 1779 CeedCall(CeedFree(&new_field_label)); 1780 return CeedError(CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPATIBLE, "Incompatible field types on sub-operator contexts. %s != %s", 1781 CeedContextFieldTypes[new_field_label->type], CeedContextFieldTypes[new_field_label_i->type]); 1782 // LCOV_EXCL_STOP 1783 } else { 1784 new_field_label->type = new_field_label_i->type; 1785 } 1786 if (new_field_label->num_values != 0 && new_field_label->num_values != new_field_label_i->num_values) { 1787 // LCOV_EXCL_START 1788 CeedCall(CeedFree(&new_field_label)); 1789 return CeedError(CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPATIBLE, 1790 "Incompatible field number of values on sub-operator contexts. %zu != %zu", new_field_label->num_values, 1791 new_field_label_i->num_values); 1792 // LCOV_EXCL_STOP 1793 } else { 1794 new_field_label->num_values = new_field_label_i->num_values; 1795 } 1796 } 1797 } 1798 } 1799 // -- Cleanup if field was found 1800 if (field_found) { 1801 *field_label = new_field_label; 1802 } else { 1803 // LCOV_EXCL_START 1804 CeedCall(CeedFree(&new_field_label->sub_labels)); 1805 CeedCall(CeedFree(&new_field_label)); 1806 *field_label = NULL; 1807 // LCOV_EXCL_STOP 1808 } 1809 } else { 1810 CeedQFunction qf; 1811 CeedQFunctionContext ctx; 1812 1813 // Single, non-composite operator 1814 CeedCall(CeedOperatorGetQFunction(op, &qf)); 1815 CeedCall(CeedQFunctionGetInnerContext(qf, &ctx)); 1816 if (ctx) { 1817 CeedCall(CeedQFunctionContextGetFieldLabel(ctx, field_name, field_label)); 1818 } else { 1819 *field_label = NULL; 1820 } 1821 } 1822 1823 // Set label in operator 1824 if (*field_label) { 1825 (*field_label)->from_op = true; 1826 1827 // Move new composite label to operator 1828 if (op->num_context_labels == 0) { 1829 CeedCall(CeedCalloc(1, &op->context_labels)); 1830 op->max_context_labels = 1; 1831 } else if (op->num_context_labels == op->max_context_labels) { 1832 CeedCall(CeedRealloc(2 * op->num_context_labels, &op->context_labels)); 1833 op->max_context_labels *= 2; 1834 } 1835 op->context_labels[op->num_context_labels] = *field_label; 1836 op->num_context_labels++; 1837 } 1838 return CEED_ERROR_SUCCESS; 1839 } 1840 1841 /** 1842 @brief Set `CeedQFunctionContext` field holding double precision values. 1843 1844 For composite operators, the values are set in all sub-operator `CeedQFunctionContext` that have a matching `field_name`. 1845 1846 @param[in,out] op `CeedOperator` 1847 @param[in] field_label Label of field to set 1848 @param[in] values Values to set 1849 1850 @return An error code: 0 - success, otherwise - failure 1851 1852 @ref User 1853 **/ 1854 int CeedOperatorSetContextDouble(CeedOperator op, CeedContextFieldLabel field_label, double *values) { 1855 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, values); 1856 } 1857 1858 /** 1859 @brief Get `CeedQFunctionContext` field holding double precision values, read-only. 1860 1861 For composite operators, the values correspond to the first sub-operator `CeedQFunctionContext` that has a matching `field_name`. 1862 1863 @param[in] op `CeedOperator` 1864 @param[in] field_label Label of field to get 1865 @param[out] num_values Number of values in the field label 1866 @param[out] values Pointer to context values 1867 1868 @return An error code: 0 - success, otherwise - failure 1869 1870 @ref User 1871 **/ 1872 int CeedOperatorGetContextDoubleRead(CeedOperator op, CeedContextFieldLabel field_label, size_t *num_values, const double **values) { 1873 return CeedOperatorContextGetGenericRead(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, num_values, values); 1874 } 1875 1876 /** 1877 @brief Restore `CeedQFunctionContext` field holding double precision values, read-only. 1878 1879 @param[in] op `CeedOperator` 1880 @param[in] field_label Label of field to restore 1881 @param[out] values Pointer to context values 1882 1883 @return An error code: 0 - success, otherwise - failure 1884 1885 @ref User 1886 **/ 1887 int CeedOperatorRestoreContextDoubleRead(CeedOperator op, CeedContextFieldLabel field_label, const double **values) { 1888 return CeedOperatorContextRestoreGenericRead(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, values); 1889 } 1890 1891 /** 1892 @brief Set `CeedQFunctionContext` field holding `int32` values. 1893 1894 For composite operators, the values are set in all sub-operator `CeedQFunctionContext` that have a matching `field_name`. 1895 1896 @param[in,out] op `CeedOperator` 1897 @param[in] field_label Label of field to set 1898 @param[in] values Values to set 1899 1900 @return An error code: 0 - success, otherwise - failure 1901 1902 @ref User 1903 **/ 1904 int CeedOperatorSetContextInt32(CeedOperator op, CeedContextFieldLabel field_label, int32_t *values) { 1905 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_INT32, values); 1906 } 1907 1908 /** 1909 @brief Get `CeedQFunctionContext` field holding `int32` values, read-only. 1910 1911 For composite operators, the values correspond to the first sub-operator `CeedQFunctionContext` that has a matching `field_name`. 1912 1913 @param[in] op `CeedOperator` 1914 @param[in] field_label Label of field to get 1915 @param[out] num_values Number of `int32` values in `values` 1916 @param[out] values Pointer to context values 1917 1918 @return An error code: 0 - success, otherwise - failure 1919 1920 @ref User 1921 **/ 1922 int CeedOperatorGetContextInt32Read(CeedOperator op, CeedContextFieldLabel field_label, size_t *num_values, const int32_t **values) { 1923 return CeedOperatorContextGetGenericRead(op, field_label, CEED_CONTEXT_FIELD_INT32, num_values, values); 1924 } 1925 1926 /** 1927 @brief Restore `CeedQFunctionContext` field holding `int32` values, read-only. 1928 1929 @param[in] op `CeedOperator` 1930 @param[in] field_label Label of field to get 1931 @param[out] values Pointer to context values 1932 1933 @return An error code: 0 - success, otherwise - failure 1934 1935 @ref User 1936 **/ 1937 int CeedOperatorRestoreContextInt32Read(CeedOperator op, CeedContextFieldLabel field_label, const int32_t **values) { 1938 return CeedOperatorContextRestoreGenericRead(op, field_label, CEED_CONTEXT_FIELD_INT32, values); 1939 } 1940 1941 /** 1942 @brief Set `CeedQFunctionContext` field holding boolean values. 1943 1944 For composite operators, the values are set in all sub-operator `CeedQFunctionContext` that have a matching `field_name`. 1945 1946 @param[in,out] op `CeedOperator` 1947 @param[in] field_label Label of field to set 1948 @param[in] values Values to set 1949 1950 @return An error code: 0 - success, otherwise - failure 1951 1952 @ref User 1953 **/ 1954 int CeedOperatorSetContextBoolean(CeedOperator op, CeedContextFieldLabel field_label, bool *values) { 1955 return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_BOOL, values); 1956 } 1957 1958 /** 1959 @brief Get `CeedQFunctionContext` field holding boolean values, read-only. 1960 1961 For composite operators, the values correspond to the first sub-operator `CeedQFunctionContext` that has a matching `field_name`. 1962 1963 @param[in] op `CeedOperator` 1964 @param[in] field_label Label of field to get 1965 @param[out] num_values Number of boolean values in `values` 1966 @param[out] values Pointer to context values 1967 1968 @return An error code: 0 - success, otherwise - failure 1969 1970 @ref User 1971 **/ 1972 int CeedOperatorGetContextBooleanRead(CeedOperator op, CeedContextFieldLabel field_label, size_t *num_values, const bool **values) { 1973 return CeedOperatorContextGetGenericRead(op, field_label, CEED_CONTEXT_FIELD_BOOL, num_values, values); 1974 } 1975 1976 /** 1977 @brief Restore `CeedQFunctionContext` field holding boolean values, read-only. 1978 1979 @param[in] op `CeedOperator` 1980 @param[in] field_label Label of field to get 1981 @param[out] values Pointer to context values 1982 1983 @return An error code: 0 - success, otherwise - failure 1984 1985 @ref User 1986 **/ 1987 int CeedOperatorRestoreContextBooleanRead(CeedOperator op, CeedContextFieldLabel field_label, const bool **values) { 1988 return CeedOperatorContextRestoreGenericRead(op, field_label, CEED_CONTEXT_FIELD_BOOL, values); 1989 } 1990 1991 /** 1992 @brief Apply `CeedOperator` to a `CeedVector`. 1993 1994 This computes the action of the operator on the specified (active) input, yielding its (active) output. 1995 All inputs and outputs must be specified using @ref CeedOperatorSetField(). 1996 1997 Note: Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable. 1998 1999 @param[in] op `CeedOperator` to apply 2000 @param[in] in `CeedVector` containing input state or @ref CEED_VECTOR_NONE if there are no active inputs 2001 @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 2002 @param[in] request Address of @ref CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE 2003 2004 @return An error code: 0 - success, otherwise - failure 2005 2006 @ref User 2007 **/ 2008 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, CeedRequest *request) { 2009 bool is_composite; 2010 2011 CeedCall(CeedOperatorCheckReady(op)); 2012 2013 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 2014 if (is_composite) { 2015 // Composite Operator 2016 if (op->ApplyComposite) { 2017 CeedCall(op->ApplyComposite(op, in, out, request)); 2018 } else { 2019 CeedInt num_suboperators; 2020 CeedOperator *sub_operators; 2021 2022 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 2023 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 2024 2025 // Zero all output vectors 2026 if (out != CEED_VECTOR_NONE) CeedCall(CeedVectorSetValue(out, 0.0)); 2027 for (CeedInt i = 0; i < num_suboperators; i++) { 2028 CeedInt num_output_fields; 2029 CeedOperatorField *output_fields; 2030 2031 CeedCall(CeedOperatorGetFields(sub_operators[i], NULL, NULL, &num_output_fields, &output_fields)); 2032 for (CeedInt j = 0; j < num_output_fields; j++) { 2033 CeedVector vec; 2034 2035 CeedCall(CeedOperatorFieldGetVector(output_fields[j], &vec)); 2036 if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) { 2037 CeedCall(CeedVectorSetValue(vec, 0.0)); 2038 } 2039 } 2040 } 2041 // Apply 2042 for (CeedInt i = 0; i < num_suboperators; i++) { 2043 CeedCall(CeedOperatorApplyAdd(sub_operators[i], in, out, request)); 2044 } 2045 } 2046 } else { 2047 // Standard Operator 2048 if (op->Apply) { 2049 CeedCall(op->Apply(op, in, out, request)); 2050 } else { 2051 CeedInt num_output_fields; 2052 CeedOperatorField *output_fields; 2053 2054 CeedCall(CeedOperatorGetFields(op, NULL, NULL, &num_output_fields, &output_fields)); 2055 // Zero all output vectors 2056 for (CeedInt i = 0; i < num_output_fields; i++) { 2057 CeedVector vec; 2058 2059 CeedCall(CeedOperatorFieldGetVector(output_fields[i], &vec)); 2060 if (vec == CEED_VECTOR_ACTIVE) vec = out; 2061 if (vec != CEED_VECTOR_NONE) CeedCall(CeedVectorSetValue(vec, 0.0)); 2062 } 2063 // Apply 2064 if (op->num_elem > 0) CeedCall(op->ApplyAdd(op, in, out, request)); 2065 } 2066 } 2067 return CEED_ERROR_SUCCESS; 2068 } 2069 2070 /** 2071 @brief Apply `CeedOperator` to a `CeedVector` and add result to output `CeedVector`. 2072 2073 This computes the action of the operator on the specified (active) input, yielding its (active) output. 2074 All inputs and outputs must be specified using @ref CeedOperatorSetField(). 2075 2076 @param[in] op `CeedOperator` to apply 2077 @param[in] in `CeedVector` containing input state or @ref CEED_VECTOR_NONE if there are no active inputs 2078 @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 2079 @param[in] request Address of @ref CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE 2080 2081 @return An error code: 0 - success, otherwise - failure 2082 2083 @ref User 2084 **/ 2085 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, CeedRequest *request) { 2086 bool is_composite; 2087 2088 CeedCall(CeedOperatorCheckReady(op)); 2089 2090 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 2091 if (is_composite) { 2092 // Composite Operator 2093 if (op->ApplyAddComposite) { 2094 CeedCall(op->ApplyAddComposite(op, in, out, request)); 2095 } else { 2096 CeedInt num_suboperators; 2097 CeedOperator *sub_operators; 2098 2099 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 2100 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 2101 for (CeedInt i = 0; i < num_suboperators; i++) { 2102 CeedCall(CeedOperatorApplyAdd(sub_operators[i], in, out, request)); 2103 } 2104 } 2105 } else if (op->num_elem > 0) { 2106 // Standard Operator 2107 CeedCall(op->ApplyAdd(op, in, out, request)); 2108 } 2109 return CEED_ERROR_SUCCESS; 2110 } 2111 2112 /** 2113 @brief Destroy temporary assembly data associated with a `CeedOperator` 2114 2115 @param[in,out] op `CeedOperator` whose assembly data to destroy 2116 2117 @return An error code: 0 - success, otherwise - failure 2118 2119 @ref User 2120 **/ 2121 int CeedOperatorAssemblyDataStrip(CeedOperator op) { 2122 bool is_composite; 2123 2124 CeedCall(CeedQFunctionAssemblyDataDestroy(&op->qf_assembled)); 2125 CeedCall(CeedOperatorAssemblyDataDestroy(&op->op_assembled)); 2126 CeedCall(CeedOperatorIsComposite(op, &is_composite)); 2127 if (is_composite) { 2128 CeedInt num_suboperators; 2129 CeedOperator *sub_operators; 2130 2131 CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators)); 2132 CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators)); 2133 for (CeedInt i = 0; i < num_suboperators; i++) { 2134 CeedCall(CeedQFunctionAssemblyDataDestroy(&sub_operators[i]->qf_assembled)); 2135 CeedCall(CeedOperatorAssemblyDataDestroy(&sub_operators[i]->op_assembled)); 2136 } 2137 } 2138 return CEED_ERROR_SUCCESS; 2139 } 2140 2141 /** 2142 @brief Destroy a `CeedOperator` 2143 2144 @param[in,out] op `CeedOperator` to destroy 2145 2146 @return An error code: 0 - success, otherwise - failure 2147 2148 @ref User 2149 **/ 2150 int CeedOperatorDestroy(CeedOperator *op) { 2151 if (!*op || --(*op)->ref_count > 0) { 2152 *op = NULL; 2153 return CEED_ERROR_SUCCESS; 2154 } 2155 // Backend destroy 2156 if ((*op)->Destroy) { 2157 CeedCall((*op)->Destroy(*op)); 2158 } 2159 // Free fields 2160 for (CeedInt i = 0; i < (*op)->num_fields; i++) { 2161 if ((*op)->input_fields[i]) { 2162 if ((*op)->input_fields[i]->elem_rstr != CEED_ELEMRESTRICTION_NONE) { 2163 CeedCall(CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_rstr)); 2164 } 2165 if ((*op)->input_fields[i]->basis != CEED_BASIS_NONE) { 2166 CeedCall(CeedBasisDestroy(&(*op)->input_fields[i]->basis)); 2167 } 2168 if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE && (*op)->input_fields[i]->vec != CEED_VECTOR_NONE) { 2169 CeedCall(CeedVectorDestroy(&(*op)->input_fields[i]->vec)); 2170 } 2171 CeedCall(CeedFree(&(*op)->input_fields[i]->field_name)); 2172 CeedCall(CeedFree(&(*op)->input_fields[i])); 2173 } 2174 } 2175 for (CeedInt i = 0; i < (*op)->num_fields; i++) { 2176 if ((*op)->output_fields[i]) { 2177 CeedCall(CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_rstr)); 2178 if ((*op)->output_fields[i]->basis != CEED_BASIS_NONE) { 2179 CeedCall(CeedBasisDestroy(&(*op)->output_fields[i]->basis)); 2180 } 2181 if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE && (*op)->output_fields[i]->vec != CEED_VECTOR_NONE) { 2182 CeedCall(CeedVectorDestroy(&(*op)->output_fields[i]->vec)); 2183 } 2184 CeedCall(CeedFree(&(*op)->output_fields[i]->field_name)); 2185 CeedCall(CeedFree(&(*op)->output_fields[i])); 2186 } 2187 } 2188 CeedCall(CeedFree(&(*op)->input_fields)); 2189 CeedCall(CeedFree(&(*op)->output_fields)); 2190 // Destroy AtPoints data 2191 CeedCall(CeedVectorDestroy(&(*op)->point_coords)); 2192 CeedCall(CeedElemRestrictionDestroy(&(*op)->rstr_points)); 2193 CeedCall(CeedElemRestrictionDestroy(&(*op)->first_points_rstr)); 2194 // Destroy assembly data (must happen before destroying sub_operators) 2195 CeedCall(CeedOperatorAssemblyDataStrip(*op)); 2196 // Destroy sub_operators 2197 for (CeedInt i = 0; i < (*op)->num_suboperators; i++) { 2198 if ((*op)->sub_operators[i]) { 2199 CeedCall(CeedOperatorDestroy(&(*op)->sub_operators[i])); 2200 } 2201 } 2202 CeedCall(CeedFree(&(*op)->sub_operators)); 2203 CeedCall(CeedQFunctionDestroy(&(*op)->qf)); 2204 CeedCall(CeedQFunctionDestroy(&(*op)->dqf)); 2205 CeedCall(CeedQFunctionDestroy(&(*op)->dqfT)); 2206 // Destroy any composite labels 2207 if ((*op)->is_composite) { 2208 for (CeedInt i = 0; i < (*op)->num_context_labels; i++) { 2209 CeedCall(CeedFree(&(*op)->context_labels[i]->sub_labels)); 2210 CeedCall(CeedFree(&(*op)->context_labels[i])); 2211 } 2212 } 2213 CeedCall(CeedFree(&(*op)->context_labels)); 2214 2215 // Destroy fallback 2216 CeedCall(CeedOperatorDestroy(&(*op)->op_fallback)); 2217 2218 CeedCall(CeedFree(&(*op)->name)); 2219 CeedCall(CeedDestroy(&(*op)->ceed)); 2220 CeedCall(CeedFree(op)); 2221 return CEED_ERROR_SUCCESS; 2222 } 2223 2224 /// @} 2225