1 // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at 2 // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights 3 // reserved. See files LICENSE and NOTICE for details. 4 // 5 // This file is part of CEED, a collection of benchmarks, miniapps, software 6 // libraries and APIs for efficient high-order finite element and spectral 7 // element discretizations for exascale applications. For more information and 8 // source code availability see http://github.com/ceed. 9 // 10 // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC, 11 // a collaborative effort of two U.S. Department of Energy organizations (Office 12 // of Science and the National Nuclear Security Administration) responsible for 13 // the planning and preparation of a capable exascale ecosystem, including 14 // software, applications, hardware, advanced system engineering and early 15 // testbed platforms, in support of the nation's exascale computing imperative. 16 17 #include <ceed/ceed.h> 18 #include <ceed/backend.h> 19 #include <ceed-impl.h> 20 #include <limits.h> 21 #include <stdbool.h> 22 #include <stdio.h> 23 #include <string.h> 24 25 /// @file 26 /// Implementation of public CeedQFunction interfaces 27 28 /// @cond DOXYGEN_SKIP 29 static struct CeedQFunction_private ceed_qfunction_none; 30 /// @endcond 31 32 /// @addtogroup CeedQFunctionUser 33 /// @{ 34 35 // Indicate that no QFunction is provided by the user 36 const CeedQFunction CEED_QFUNCTION_NONE = &ceed_qfunction_none; 37 38 /// @} 39 40 /// @cond DOXYGEN_SKIP 41 static struct { 42 char name[CEED_MAX_RESOURCE_LEN]; 43 char source[CEED_MAX_RESOURCE_LEN]; 44 CeedInt vec_length; 45 CeedQFunctionUser f; 46 int (*init)(Ceed ceed, const char *name, CeedQFunction qf); 47 } gallery_qfunctions[1024]; 48 static size_t num_qfunctions; 49 /// @endcond 50 51 /// ---------------------------------------------------------------------------- 52 /// CeedQFunction Library Internal Functions 53 /// ---------------------------------------------------------------------------- 54 /// @addtogroup CeedQFunctionDeveloper 55 /// @{ 56 57 /** 58 @brief Register a gallery QFunction 59 60 @param name Name for this backend to respond to 61 @param source Absolute path to source of QFunction, 62 "\path\CEED_DIR\gallery\folder\file.h:function_name" 63 @param vec_length Vector length. Caller must ensure that number of quadrature 64 points is a multiple of vec_length. 65 @param f Function pointer to evaluate action at quadrature points. 66 See \ref CeedQFunctionUser. 67 @param init Initialization function called by CeedQFunctionInit() when the 68 QFunction is selected. 69 70 @return An error code: 0 - success, otherwise - failure 71 72 @ref Developer 73 **/ 74 int CeedQFunctionRegister(const char *name, const char *source, 75 CeedInt vec_length, CeedQFunctionUser f, 76 int (*init)(Ceed, const char *, CeedQFunction)) { 77 if (num_qfunctions >= sizeof(gallery_qfunctions) / sizeof( 78 gallery_qfunctions[0])) 79 // LCOV_EXCL_START 80 return CeedError(NULL, CEED_ERROR_MAJOR, "Too many gallery QFunctions"); 81 // LCOV_EXCL_STOP 82 83 strncpy(gallery_qfunctions[num_qfunctions].name, name, CEED_MAX_RESOURCE_LEN); 84 gallery_qfunctions[num_qfunctions].name[CEED_MAX_RESOURCE_LEN-1] = 0; 85 strncpy(gallery_qfunctions[num_qfunctions].source, source, 86 CEED_MAX_RESOURCE_LEN); 87 gallery_qfunctions[num_qfunctions].source[CEED_MAX_RESOURCE_LEN-1] = 0; 88 gallery_qfunctions[num_qfunctions].vec_length = vec_length; 89 gallery_qfunctions[num_qfunctions].f = f; 90 gallery_qfunctions[num_qfunctions].init = init; 91 num_qfunctions++; 92 return CEED_ERROR_SUCCESS; 93 } 94 95 /** 96 @brief Set a CeedQFunction field, used by CeedQFunctionAddInput/Output 97 98 @param f CeedQFunctionField 99 @param field_name Name of QFunction field 100 @param size Size of QFunction field, (num_comp * dim) for @ref CEED_EVAL_GRAD or 101 (num_comp * 1) for @ref CEED_EVAL_NONE, @ref CEED_EVAL_INTERP, and @ref CEED_EVAL_WEIGHT 102 @param eval_mode \ref CEED_EVAL_NONE to use values directly, 103 \ref CEED_EVAL_INTERP to use interpolated values, 104 \ref CEED_EVAL_GRAD to use gradients, 105 \ref CEED_EVAL_WEIGHT to use quadrature weights. 106 107 @return An error code: 0 - success, otherwise - failure 108 109 @ref Developer 110 **/ 111 static int CeedQFunctionFieldSet(CeedQFunctionField *f,const char *field_name, 112 CeedInt size, CeedEvalMode eval_mode) { 113 size_t len = strlen(field_name); 114 char *tmp; 115 int ierr; 116 117 ierr = CeedCalloc(1, f); CeedChk(ierr); 118 ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr); 119 memcpy(tmp, field_name, len+1); 120 (*f)->field_name = tmp; 121 (*f)->size = size; 122 (*f)->eval_mode = eval_mode; 123 return CEED_ERROR_SUCCESS; 124 } 125 126 /** 127 @brief View a field of a CeedQFunction 128 129 @param[in] field QFunction field to view 130 @param[in] field_number Number of field being viewed 131 @param[in] in true for input field, false for output 132 @param[in] stream Stream to view to, e.g., stdout 133 134 @return An error code: 0 - success, otherwise - failure 135 136 @ref Utility 137 **/ 138 static int CeedQFunctionFieldView(CeedQFunctionField field, 139 CeedInt field_number, 140 bool in, FILE *stream) { 141 const char *inout = in ? "Input" : "Output"; 142 fprintf(stream, " %s Field [%d]:\n" 143 " Name: \"%s\"\n" 144 " Size: %d\n" 145 " EvalMode: \"%s\"\n", 146 inout, field_number, field->field_name, field->size, 147 CeedEvalModes[field->eval_mode]); 148 return CEED_ERROR_SUCCESS; 149 } 150 151 /** 152 @brief Set flag to determine if Fortran interface is used 153 154 @param qf CeedQFunction 155 @param status Boolean value to set as Fortran status 156 157 @return An error code: 0 - success, otherwise - failure 158 159 @ref Backend 160 **/ 161 int CeedQFunctionSetFortranStatus(CeedQFunction qf, bool status) { 162 qf->fortran_status = status; 163 return CEED_ERROR_SUCCESS; 164 } 165 166 /// @} 167 168 /// ---------------------------------------------------------------------------- 169 /// CeedQFunction Backend API 170 /// ---------------------------------------------------------------------------- 171 /// @addtogroup CeedQFunctionBackend 172 /// @{ 173 174 /** 175 @brief Get the Ceed associated with a CeedQFunction 176 177 @param qf CeedQFunction 178 @param[out] ceed Variable to store Ceed 179 180 @return An error code: 0 - success, otherwise - failure 181 182 @ref Backend 183 **/ 184 int CeedQFunctionGetCeed(CeedQFunction qf, Ceed *ceed) { 185 *ceed = qf->ceed; 186 return CEED_ERROR_SUCCESS; 187 } 188 189 /** 190 @brief Get the vector length of a CeedQFunction 191 192 @param qf CeedQFunction 193 @param[out] vec_length Variable to store vector length 194 195 @return An error code: 0 - success, otherwise - failure 196 197 @ref Backend 198 **/ 199 int CeedQFunctionGetVectorLength(CeedQFunction qf, CeedInt *vec_length) { 200 *vec_length = qf->vec_length; 201 return CEED_ERROR_SUCCESS; 202 } 203 204 /** 205 @brief Get the number of inputs and outputs to a CeedQFunction 206 207 @param qf CeedQFunction 208 @param[out] num_input Variable to store number of input fields 209 @param[out] num_output Variable to store number of output fields 210 211 @return An error code: 0 - success, otherwise - failure 212 213 @ref Backend 214 **/ 215 int CeedQFunctionGetNumArgs(CeedQFunction qf, CeedInt *num_input, 216 CeedInt *num_output) { 217 if (num_input) *num_input = qf->num_input_fields; 218 if (num_output) *num_output = qf->num_output_fields; 219 return CEED_ERROR_SUCCESS; 220 } 221 222 /** 223 @brief Get the source path string for a CeedQFunction 224 225 @param qf CeedQFunction 226 @param[out] source Variable to store source path string 227 228 @return An error code: 0 - success, otherwise - failure 229 230 @ref Backend 231 **/ 232 int CeedQFunctionGetSourcePath(CeedQFunction qf, char **source) { 233 *source = (char *) qf->source_path; 234 return CEED_ERROR_SUCCESS; 235 } 236 237 /** 238 @brief Get the User Function for a CeedQFunction 239 240 @param qf CeedQFunction 241 @param[out] f Variable to store user function 242 243 @return An error code: 0 - success, otherwise - failure 244 245 @ref Backend 246 **/ 247 int CeedQFunctionGetUserFunction(CeedQFunction qf, CeedQFunctionUser *f) { 248 *f = qf->function; 249 return CEED_ERROR_SUCCESS; 250 } 251 252 /** 253 @brief Get global context for a CeedQFunction. 254 Note: For QFunctions from the Fortran interface, this 255 function will return the Fortran context 256 CeedQFunctionContext. 257 258 @param qf CeedQFunction 259 @param[out] ctx Variable to store CeedQFunctionContext 260 261 @return An error code: 0 - success, otherwise - failure 262 263 @ref Backend 264 **/ 265 int CeedQFunctionGetContext(CeedQFunction qf, CeedQFunctionContext *ctx) { 266 *ctx = qf->ctx; 267 return CEED_ERROR_SUCCESS; 268 } 269 270 /** 271 @brief Get true user context for a CeedQFunction 272 Note: For all QFunctions this function will return the user 273 CeedQFunctionContext and not interface context 274 CeedQFunctionContext, if any such object exists. 275 276 @param qf CeedQFunction 277 @param[out] ctx Variable to store CeedQFunctionContext 278 279 @return An error code: 0 - success, otherwise - failure 280 @ref Backend 281 **/ 282 int CeedQFunctionGetInnerContext(CeedQFunction qf, CeedQFunctionContext *ctx) { 283 int ierr; 284 if (qf->fortran_status) { 285 CeedFortranContext fortran_ctx = NULL; 286 ierr = CeedQFunctionContextGetData(qf->ctx, CEED_MEM_HOST, &fortran_ctx); 287 CeedChk(ierr); 288 *ctx = fortran_ctx->innerctx; 289 ierr = CeedQFunctionContextRestoreData(qf->ctx, (void *)&fortran_ctx); 290 CeedChk(ierr); 291 } else { 292 *ctx = qf->ctx; 293 } 294 return CEED_ERROR_SUCCESS; 295 } 296 297 /** 298 @brief Determine if QFunction is identity 299 300 @param qf CeedQFunction 301 @param[out] is_identity Variable to store identity status 302 303 @return An error code: 0 - success, otherwise - failure 304 305 @ref Backend 306 **/ 307 int CeedQFunctionIsIdentity(CeedQFunction qf, bool *is_identity) { 308 *is_identity = qf->identity; 309 return CEED_ERROR_SUCCESS; 310 } 311 312 /** 313 @brief Get backend data of a CeedQFunction 314 315 @param qf CeedQFunction 316 @param[out] data Variable to store data 317 318 @return An error code: 0 - success, otherwise - failure 319 320 @ref Backend 321 **/ 322 int CeedQFunctionGetData(CeedQFunction qf, void *data) { 323 *(void **)data = qf->data; 324 return CEED_ERROR_SUCCESS; 325 } 326 327 /** 328 @brief Set backend data of a CeedQFunction 329 330 @param[out] qf CeedQFunction 331 @param data Data to set 332 333 @return An error code: 0 - success, otherwise - failure 334 335 @ref Backend 336 **/ 337 int CeedQFunctionSetData(CeedQFunction qf, void *data) { 338 qf->data = data; 339 return CEED_ERROR_SUCCESS; 340 } 341 342 /** 343 @brief Get the CeedQFunctionFields of a CeedQFunction 344 345 @param qf CeedQFunction 346 @param[out] input_fields Variable to store input_fields 347 @param[out] output_fields Variable to store output_fields 348 349 @return An error code: 0 - success, otherwise - failure 350 351 @ref Backend 352 **/ 353 int CeedQFunctionGetFields(CeedQFunction qf, CeedQFunctionField **input_fields, 354 CeedQFunctionField **output_fields) { 355 if (input_fields) *input_fields = qf->input_fields; 356 if (output_fields) *output_fields = qf->output_fields; 357 return CEED_ERROR_SUCCESS; 358 } 359 360 /** 361 @brief Get the name of a CeedQFunctionField 362 363 @param qf_field CeedQFunctionField 364 @param[out] field_name Variable to store the field name 365 366 @return An error code: 0 - success, otherwise - failure 367 368 @ref Backend 369 **/ 370 int CeedQFunctionFieldGetName(CeedQFunctionField qf_field, char **field_name) { 371 *field_name = (char *)qf_field->field_name; 372 return CEED_ERROR_SUCCESS; 373 } 374 375 /** 376 @brief Get the number of components of a CeedQFunctionField 377 378 @param qf_field CeedQFunctionField 379 @param[out] size Variable to store the size of the field 380 381 @return An error code: 0 - success, otherwise - failure 382 383 @ref Backend 384 **/ 385 int CeedQFunctionFieldGetSize(CeedQFunctionField qf_field, CeedInt *size) { 386 *size = qf_field->size; 387 return CEED_ERROR_SUCCESS; 388 } 389 390 /** 391 @brief Get the CeedEvalMode of a CeedQFunctionField 392 393 @param qf_field CeedQFunctionField 394 @param[out] eval_mode Variable to store the field evaluation mode 395 396 @return An error code: 0 - success, otherwise - failure 397 398 @ref Backend 399 **/ 400 int CeedQFunctionFieldGetEvalMode(CeedQFunctionField qf_field, 401 CeedEvalMode *eval_mode) { 402 *eval_mode = qf_field->eval_mode; 403 return CEED_ERROR_SUCCESS; 404 } 405 406 /// @} 407 408 /// ---------------------------------------------------------------------------- 409 /// CeedQFunction Public API 410 /// ---------------------------------------------------------------------------- 411 /// @addtogroup CeedQFunctionUser 412 /// @{ 413 414 /** 415 @brief Create a CeedQFunction for evaluating interior (volumetric) terms. 416 417 @param ceed A Ceed object where the CeedQFunction will be created 418 @param vec_length Vector length. Caller must ensure that number of quadrature 419 points is a multiple of vec_length. 420 @param f Function pointer to evaluate action at quadrature points. 421 See \ref CeedQFunctionUser. 422 @param source Absolute path to source of QFunction, 423 "\abs_path\file.h:function_name". 424 For support across all backends, this source must only 425 contain constructs supported by C99, C++11, and CUDA. 426 @param[out] qf Address of the variable where the newly created 427 CeedQFunction will be stored 428 429 @return An error code: 0 - success, otherwise - failure 430 431 See \ref CeedQFunctionUser for details on the call-back function @a f's 432 arguments. 433 434 @ref User 435 **/ 436 int CeedQFunctionCreateInterior(Ceed ceed, CeedInt vec_length, 437 CeedQFunctionUser f, 438 const char *source, CeedQFunction *qf) { 439 int ierr; 440 char *source_copy; 441 442 if (!ceed->QFunctionCreate) { 443 Ceed delegate; 444 ierr = CeedGetObjectDelegate(ceed, &delegate, "QFunction"); CeedChk(ierr); 445 446 if (!delegate) 447 // LCOV_EXCL_START 448 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 449 "Backend does not support QFunctionCreate"); 450 // LCOV_EXCL_STOP 451 452 ierr = CeedQFunctionCreateInterior(delegate, vec_length, f, source, qf); 453 CeedChk(ierr); 454 return CEED_ERROR_SUCCESS; 455 } 456 457 ierr = CeedCalloc(1, qf); CeedChk(ierr); 458 (*qf)->ceed = ceed; 459 ceed->ref_count++; 460 (*qf)->ref_count = 1; 461 (*qf)->vec_length = vec_length; 462 (*qf)->identity = 0; 463 (*qf)->function = f; 464 size_t slen = strlen(source) + 1; 465 ierr = CeedMalloc(slen, &source_copy); CeedChk(ierr); 466 memcpy(source_copy, source, slen); 467 (*qf)->source_path = source_copy; 468 ierr = CeedCalloc(16, &(*qf)->input_fields); CeedChk(ierr); 469 ierr = CeedCalloc(16, &(*qf)->output_fields); CeedChk(ierr); 470 ierr = ceed->QFunctionCreate(*qf); CeedChk(ierr); 471 return CEED_ERROR_SUCCESS; 472 } 473 474 /** 475 @brief Create a CeedQFunction for evaluating interior (volumetric) terms by name. 476 477 @param ceed A Ceed object where the CeedQFunction will be created 478 @param name Name of QFunction to use from gallery 479 @param[out] qf Address of the variable where the newly created 480 CeedQFunction will be stored 481 482 @return An error code: 0 - success, otherwise - failure 483 484 @ref User 485 **/ 486 int CeedQFunctionCreateInteriorByName(Ceed ceed, const char *name, 487 CeedQFunction *qf) { 488 int ierr; 489 size_t match_len = 0, match_idx = UINT_MAX; 490 char *name_copy; 491 492 ierr = CeedQFunctionRegisterAll(); CeedChk(ierr); 493 // Find matching backend 494 if (!name) return CeedError(ceed, CEED_ERROR_INCOMPLETE, 495 "No QFunction name provided"); 496 for (size_t i=0; i<num_qfunctions; i++) { 497 size_t n; 498 const char *curr_name = gallery_qfunctions[i].name; 499 for (n = 0; curr_name[n] && curr_name[n] == name[n]; n++) {} 500 if (n > match_len) { 501 match_len = n; 502 match_idx = i; 503 } 504 } 505 if (!match_len) 506 // LCOV_EXCL_START 507 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "No suitable gallery QFunction"); 508 // LCOV_EXCL_STOP 509 510 // Create QFunction 511 ierr = CeedQFunctionCreateInterior(ceed, 512 gallery_qfunctions[match_idx].vec_length, 513 gallery_qfunctions[match_idx].f, 514 gallery_qfunctions[match_idx].source, qf); 515 CeedChk(ierr); 516 517 // QFunction specific setup 518 ierr = gallery_qfunctions[match_idx].init(ceed, name, *qf); CeedChk(ierr); 519 520 // Copy name 521 size_t slen = strlen(name) + 1; 522 ierr = CeedMalloc(slen, &name_copy); CeedChk(ierr); 523 memcpy(name_copy, name, slen); 524 (*qf)->qf_name = name_copy; 525 return CEED_ERROR_SUCCESS; 526 } 527 528 /** 529 @brief Create an identity CeedQFunction. Inputs are written into outputs in 530 the order given. This is useful for CeedOperators that can be 531 represented with only the action of a CeedRestriction and CeedBasis, 532 such as restriction and prolongation operators for p-multigrid. 533 Backends may optimize CeedOperators with this CeedQFunction to avoid 534 the copy of input data to output fields by using the same memory 535 location for both. 536 537 @param ceed A Ceed object where the CeedQFunction will be created 538 @param[in] size Size of the QFunction fields 539 @param[in] in_mode CeedEvalMode for input to CeedQFunction 540 @param[in] out_mode CeedEvalMode for output to CeedQFunction 541 @param[out] qf Address of the variable where the newly created 542 CeedQFunction will be stored 543 544 @return An error code: 0 - success, otherwise - failure 545 546 @ref User 547 **/ 548 int CeedQFunctionCreateIdentity(Ceed ceed, CeedInt size, CeedEvalMode in_mode, 549 CeedEvalMode out_mode, CeedQFunction *qf) { 550 int ierr; 551 552 if (in_mode == CEED_EVAL_NONE && out_mode == CEED_EVAL_NONE) 553 // LCOV_EXCL_START 554 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 555 "CEED_EVAL_NONE for a both the input and " 556 "output does not make sense with an identity QFunction"); 557 // LCOV_EXCL_STOP 558 559 ierr = CeedQFunctionCreateInteriorByName(ceed, "Identity", qf); CeedChk(ierr); 560 ierr = CeedQFunctionAddInput(*qf, "input", size, in_mode); CeedChk(ierr); 561 ierr = CeedQFunctionAddOutput(*qf, "output", size, out_mode); CeedChk(ierr); 562 563 (*qf)->identity = 1; 564 CeedInt *size_data; 565 ierr = CeedCalloc(1, &size_data); CeedChk(ierr); 566 size_data[0] = size; 567 CeedQFunctionContext ctx; 568 ierr = CeedQFunctionContextCreate(ceed, &ctx); CeedChk(ierr); 569 ierr = CeedQFunctionContextSetData(ctx, CEED_MEM_HOST, CEED_OWN_POINTER, 570 sizeof(*size_data), (void *)size_data); 571 CeedChk(ierr); 572 ierr = CeedQFunctionSetContext(*qf, ctx); CeedChk(ierr); 573 ierr = CeedQFunctionContextDestroy(&ctx); CeedChk(ierr); 574 return CEED_ERROR_SUCCESS; 575 } 576 577 /** 578 @brief Add a CeedQFunction input 579 580 @param qf CeedQFunction 581 @param field_name Name of QFunction field 582 @param size Size of QFunction field, (num_comp * dim) for @ref CEED_EVAL_GRAD or 583 (num_comp * 1) for @ref CEED_EVAL_NONE and @ref CEED_EVAL_INTERP 584 @param eval_mode \ref CEED_EVAL_NONE to use values directly, 585 \ref CEED_EVAL_INTERP to use interpolated values, 586 \ref CEED_EVAL_GRAD to use gradients. 587 588 @return An error code: 0 - success, otherwise - failure 589 590 @ref User 591 **/ 592 int CeedQFunctionAddInput(CeedQFunction qf, const char *field_name, 593 CeedInt size, 594 CeedEvalMode eval_mode) { 595 if (qf->operators_set) 596 // LCOV_EXCL_START 597 return CeedError(qf->ceed, CEED_ERROR_MAJOR, 598 "QFunction cannot be changed when in use by an operator"); 599 // LCOV_EXCL_STOP 600 if ((eval_mode == CEED_EVAL_WEIGHT) && (size != 1)) 601 // LCOV_EXCL_START 602 return CeedError(qf->ceed, CEED_ERROR_DIMENSION, 603 "CEED_EVAL_WEIGHT should have size 1"); 604 // LCOV_EXCL_STOP 605 int ierr = CeedQFunctionFieldSet(&qf->input_fields[qf->num_input_fields], 606 field_name, size, eval_mode); 607 CeedChk(ierr); 608 qf->num_input_fields++; 609 return CEED_ERROR_SUCCESS; 610 } 611 612 /** 613 @brief Add a CeedQFunction output 614 615 @param qf CeedQFunction 616 @param field_name Name of QFunction field 617 @param size Size of QFunction field, (num_comp * dim) for @ref CEED_EVAL_GRAD or 618 (num_comp * 1) for @ref CEED_EVAL_NONE and @ref CEED_EVAL_INTERP 619 @param eval_mode \ref CEED_EVAL_NONE to use values directly, 620 \ref CEED_EVAL_INTERP to use interpolated values, 621 \ref CEED_EVAL_GRAD to use gradients. 622 623 @return An error code: 0 - success, otherwise - failure 624 625 @ref User 626 **/ 627 int CeedQFunctionAddOutput(CeedQFunction qf, const char *field_name, 628 CeedInt size, CeedEvalMode eval_mode) { 629 if (qf->operators_set) 630 // LCOV_EXCL_START 631 return CeedError(qf->ceed, CEED_ERROR_MAJOR, 632 "QFunction cannot be changed when in use by an operator"); 633 // LCOV_EXCL_STOP 634 if (eval_mode == CEED_EVAL_WEIGHT) 635 // LCOV_EXCL_START 636 return CeedError(qf->ceed, CEED_ERROR_DIMENSION, 637 "Cannot create QFunction output with " 638 "CEED_EVAL_WEIGHT"); 639 // LCOV_EXCL_STOP 640 int ierr = CeedQFunctionFieldSet(&qf->output_fields[qf->num_output_fields], 641 field_name, size, eval_mode); 642 CeedChk(ierr); 643 qf->num_output_fields++; 644 return CEED_ERROR_SUCCESS; 645 } 646 647 /** 648 @brief Set global context for a CeedQFunction 649 650 @param qf CeedQFunction 651 @param ctx Context data to set 652 653 @return An error code: 0 - success, otherwise - failure 654 655 @ref User 656 **/ 657 int CeedQFunctionSetContext(CeedQFunction qf, CeedQFunctionContext ctx) { 658 qf->ctx = ctx; 659 ctx->ref_count++; 660 return CEED_ERROR_SUCCESS; 661 } 662 663 /** 664 @brief View a CeedQFunction 665 666 @param[in] qf CeedQFunction to view 667 @param[in] stream Stream to write; typically stdout/stderr or a file 668 669 @return Error code: 0 - success, otherwise - failure 670 671 @ref User 672 **/ 673 int CeedQFunctionView(CeedQFunction qf, FILE *stream) { 674 int ierr; 675 676 fprintf(stream, "%sCeedQFunction %s\n", 677 qf->qf_name ? "Gallery " : "User ", qf->qf_name ? qf->qf_name : ""); 678 679 fprintf(stream, " %d Input Field%s:\n", qf->num_input_fields, 680 qf->num_input_fields>1 ? "s" : ""); 681 for (CeedInt i=0; i<qf->num_input_fields; i++) { 682 ierr = CeedQFunctionFieldView(qf->input_fields[i], i, 1, stream); 683 CeedChk(ierr); 684 } 685 686 fprintf(stream, " %d Output Field%s:\n", qf->num_output_fields, 687 qf->num_output_fields>1 ? "s" : ""); 688 for (CeedInt i=0; i<qf->num_output_fields; i++) { 689 ierr = CeedQFunctionFieldView(qf->output_fields[i], i, 0, stream); 690 CeedChk(ierr); 691 } 692 return CEED_ERROR_SUCCESS; 693 } 694 695 /** 696 @brief Apply the action of a CeedQFunction 697 698 @param qf CeedQFunction 699 @param Q Number of quadrature points 700 @param[in] u Array of input CeedVectors 701 @param[out] v Array of output CeedVectors 702 703 @return An error code: 0 - success, otherwise - failure 704 705 @ref User 706 **/ 707 int CeedQFunctionApply(CeedQFunction qf, CeedInt Q, 708 CeedVector *u, CeedVector *v) { 709 int ierr; 710 if (!qf->Apply) 711 // LCOV_EXCL_START 712 return CeedError(qf->ceed, CEED_ERROR_UNSUPPORTED, 713 "Backend does not support QFunctionApply"); 714 // LCOV_EXCL_STOP 715 if (Q % qf->vec_length) 716 // LCOV_EXCL_START 717 return CeedError(qf->ceed, CEED_ERROR_DIMENSION, 718 "Number of quadrature points %d must be a " 719 "multiple of %d", Q, qf->vec_length); 720 // LCOV_EXCL_STOP 721 ierr = qf->Apply(qf, Q, u, v); CeedChk(ierr); 722 return CEED_ERROR_SUCCESS; 723 } 724 725 /** 726 @brief Destroy a CeedQFunction 727 728 @param qf CeedQFunction to destroy 729 730 @return An error code: 0 - success, otherwise - failure 731 732 @ref User 733 **/ 734 int CeedQFunctionDestroy(CeedQFunction *qf) { 735 int ierr; 736 737 if (!*qf || --(*qf)->ref_count > 0) return CEED_ERROR_SUCCESS; 738 // Backend destroy 739 if ((*qf)->Destroy) { 740 ierr = (*qf)->Destroy(*qf); CeedChk(ierr); 741 } 742 // Free fields 743 for (int i=0; i<(*qf)->num_input_fields; i++) { 744 ierr = CeedFree(&(*(*qf)->input_fields[i]).field_name); CeedChk(ierr); 745 ierr = CeedFree(&(*qf)->input_fields[i]); CeedChk(ierr); 746 } 747 for (int i=0; i<(*qf)->num_output_fields; i++) { 748 ierr = CeedFree(&(*(*qf)->output_fields[i]).field_name); CeedChk(ierr); 749 ierr = CeedFree(&(*qf)->output_fields[i]); CeedChk(ierr); 750 } 751 ierr = CeedFree(&(*qf)->input_fields); CeedChk(ierr); 752 ierr = CeedFree(&(*qf)->output_fields); CeedChk(ierr); 753 754 // User context data object 755 ierr = CeedQFunctionContextDestroy(&(*qf)->ctx); CeedChk(ierr); 756 757 ierr = CeedFree(&(*qf)->source_path); CeedChk(ierr); 758 ierr = CeedFree(&(*qf)->qf_name); CeedChk(ierr); 759 ierr = CeedDestroy(&(*qf)->ceed); CeedChk(ierr); 760 ierr = CeedFree(qf); CeedChk(ierr); 761 return CEED_ERROR_SUCCESS; 762 } 763 764 /// @} 765