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