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