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