1 // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors. 2 // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 3 // 4 // SPDX-License-Identifier: BSD-2-Clause 5 // 6 // This file is part of CEED: http://github.com/ceed 7 8 #include <ceed-impl.h> 9 #include <ceed.h> 10 #include <ceed/backend.h> 11 #include <ceed/jit-tools.h> 12 #include <limits.h> 13 #include <stdbool.h> 14 #include <stdio.h> 15 #include <string.h> 16 17 /// @file 18 /// Implementation of public CeedQFunction interfaces 19 20 /// @cond DOXYGEN_SKIP 21 static struct CeedQFunction_private ceed_qfunction_none; 22 /// @endcond 23 24 /// @addtogroup CeedQFunctionUser 25 /// @{ 26 27 // Indicate that no QFunction is provided by the user 28 const CeedQFunction CEED_QFUNCTION_NONE = &ceed_qfunction_none; 29 30 /// @} 31 32 /// @cond DOXYGEN_SKIP 33 static struct { 34 char name[CEED_MAX_RESOURCE_LEN]; 35 char source[CEED_MAX_RESOURCE_LEN]; 36 CeedInt vec_length; 37 CeedQFunctionUser f; 38 int (*init)(Ceed ceed, const char *name, CeedQFunction qf); 39 } gallery_qfunctions[1024]; 40 static size_t num_qfunctions; 41 /// @endcond 42 43 /// ---------------------------------------------------------------------------- 44 /// CeedQFunction Library Internal Functions 45 /// ---------------------------------------------------------------------------- 46 /// @addtogroup CeedQFunctionDeveloper 47 /// @{ 48 49 /** 50 @brief Register a gallery QFunction 51 52 @param[in] name Name for this backend to respond to 53 @param[in] source Absolute path to source of QFunction, "\path\CEED_DIR\gallery\folder\file.h:function_name" 54 @param[in] vec_length Vector length. Caller must ensure that number of quadrature points is a multiple of vec_length. 55 @param[in] f Function pointer to evaluate action at quadrature points. 56 See \ref CeedQFunctionUser. 57 @param[in] init Initialization function called by CeedQFunctionInit() when the QFunction is selected. 58 59 @return An error code: 0 - success, otherwise - failure 60 61 @ref Developer 62 **/ 63 int CeedQFunctionRegister(const char *name, const char *source, CeedInt vec_length, CeedQFunctionUser f, 64 int (*init)(Ceed, const char *, CeedQFunction)) { 65 if (num_qfunctions >= sizeof(gallery_qfunctions) / sizeof(gallery_qfunctions[0])) { 66 // LCOV_EXCL_START 67 return CeedError(NULL, CEED_ERROR_MAJOR, "Too many gallery QFunctions"); 68 // LCOV_EXCL_STOP 69 } 70 71 CeedDebugEnv("Gallery Register: %s", name); 72 73 const char *relative_file_path; 74 CeedCall(CeedGetJitRelativePath(source, &relative_file_path)); 75 76 strncpy(gallery_qfunctions[num_qfunctions].name, name, CEED_MAX_RESOURCE_LEN); 77 gallery_qfunctions[num_qfunctions].name[CEED_MAX_RESOURCE_LEN - 1] = 0; 78 strncpy(gallery_qfunctions[num_qfunctions].source, relative_file_path, CEED_MAX_RESOURCE_LEN); 79 gallery_qfunctions[num_qfunctions].source[CEED_MAX_RESOURCE_LEN - 1] = 0; 80 gallery_qfunctions[num_qfunctions].vec_length = vec_length; 81 gallery_qfunctions[num_qfunctions].f = f; 82 gallery_qfunctions[num_qfunctions].init = init; 83 num_qfunctions++; 84 return CEED_ERROR_SUCCESS; 85 } 86 87 /** 88 @brief Set a CeedQFunction field, used by CeedQFunctionAddInput/Output 89 90 @param[out] f CeedQFunctionField 91 @param[in] field_name Name of QFunction field 92 @param[in] size Size of QFunction field, (num_comp * dim) for @ref CEED_EVAL_GRAD or (num_comp * 1) for @ref CEED_EVAL_NONE, @ref 93 CEED_EVAL_INTERP, and @ref CEED_EVAL_WEIGHT 94 @param[in] eval_mode \ref CEED_EVAL_NONE to use values directly, 95 \ref CEED_EVAL_INTERP to use interpolated values, 96 \ref CEED_EVAL_GRAD to use gradients, 97 \ref CEED_EVAL_WEIGHT to use quadrature weights. 98 99 @return An error code: 0 - success, otherwise - failure 100 101 @ref Developer 102 **/ 103 static int CeedQFunctionFieldSet(CeedQFunctionField *f, const char *field_name, CeedInt size, CeedEvalMode eval_mode) { 104 CeedCall(CeedCalloc(1, f)); 105 CeedCall(CeedStringAllocCopy(field_name, (char **)&(*f)->field_name)); 106 (*f)->size = size; 107 (*f)->eval_mode = eval_mode; 108 return CEED_ERROR_SUCCESS; 109 } 110 111 /** 112 @brief View a field of a CeedQFunction 113 114 @param[in] field QFunction field to view 115 @param[in] field_number Number of field being viewed 116 @param[in] in true for input field, false for output 117 @param[in] stream Stream to view to, e.g., stdout 118 119 @return An error code: 0 - success, otherwise - failure 120 121 @ref Utility 122 **/ 123 static int CeedQFunctionFieldView(CeedQFunctionField field, CeedInt field_number, bool in, FILE *stream) { 124 const char *inout = in ? "Input" : "Output"; 125 char *field_name; 126 CeedCall(CeedQFunctionFieldGetName(field, &field_name)); 127 CeedInt size; 128 CeedCall(CeedQFunctionFieldGetSize(field, &size)); 129 CeedEvalMode eval_mode; 130 CeedCall(CeedQFunctionFieldGetEvalMode(field, &eval_mode)); 131 fprintf(stream, 132 " %s field %" CeedInt_FMT 133 ":\n" 134 " Name: \"%s\"\n" 135 " Size: %" CeedInt_FMT 136 "\n" 137 " EvalMode: \"%s\"\n", 138 inout, field_number, field_name, size, CeedEvalModes[eval_mode]); 139 return CEED_ERROR_SUCCESS; 140 } 141 142 /** 143 @brief Set flag to determine if Fortran interface is used 144 145 @param[in,out] qf CeedQFunction 146 @param[in] status Boolean value to set as Fortran status 147 148 @return An error code: 0 - success, otherwise - failure 149 150 @ref Backend 151 **/ 152 int CeedQFunctionSetFortranStatus(CeedQFunction qf, bool status) { 153 qf->is_fortran = status; 154 return CEED_ERROR_SUCCESS; 155 } 156 157 /// @} 158 159 /// ---------------------------------------------------------------------------- 160 /// CeedQFunction Backend API 161 /// ---------------------------------------------------------------------------- 162 /// @addtogroup CeedQFunctionBackend 163 /// @{ 164 165 /** 166 @brief Get the vector length of a CeedQFunction 167 168 @param[in] qf CeedQFunction 169 @param[out] vec_length Variable to store vector length 170 171 @return An error code: 0 - success, otherwise - failure 172 173 @ref Backend 174 **/ 175 int CeedQFunctionGetVectorLength(CeedQFunction qf, CeedInt *vec_length) { 176 *vec_length = qf->vec_length; 177 return CEED_ERROR_SUCCESS; 178 } 179 180 /** 181 @brief Get the number of inputs and outputs to a CeedQFunction 182 183 @param[in] qf CeedQFunction 184 @param[out] num_input Variable to store number of input fields 185 @param[out] num_output Variable to store number of output fields 186 187 @return An error code: 0 - success, otherwise - failure 188 189 @ref Backend 190 **/ 191 int CeedQFunctionGetNumArgs(CeedQFunction qf, CeedInt *num_input, CeedInt *num_output) { 192 if (num_input) *num_input = qf->num_input_fields; 193 if (num_output) *num_output = qf->num_output_fields; 194 return CEED_ERROR_SUCCESS; 195 } 196 197 /** 198 @brief Get the name of the user function for a CeedQFunction 199 200 @param[in] qf CeedQFunction 201 @param[out] kernel_name Variable to store source path string 202 203 @return An error code: 0 - success, otherwise - failure 204 205 @ref Backend 206 **/ 207 int CeedQFunctionGetKernelName(CeedQFunction qf, char **kernel_name) { 208 if (!qf->kernel_name) { 209 Ceed ceed; 210 char *kernel_name_copy; 211 CeedCall(CeedQFunctionGetCeed(qf, &ceed)); 212 213 if (qf->user_source) { 214 const char *kernel_name = strrchr(qf->user_source, ':') + 1; 215 size_t kernel_name_len = strlen(kernel_name); 216 217 CeedCall(CeedCalloc(kernel_name_len + 1, &kernel_name_copy)); 218 memcpy(kernel_name_copy, kernel_name, kernel_name_len); 219 } else { 220 CeedCall(CeedCalloc(1, &kernel_name_copy)); 221 } 222 qf->kernel_name = kernel_name_copy; 223 } 224 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[in] 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 if (!qf->source_path && qf->user_source) { 241 Ceed ceed; 242 bool is_absolute_path; 243 char *absolute_path, *source_path_copy; 244 const char *kernel_name = strrchr(qf->user_source, ':') + 1; 245 size_t kernel_name_len = strlen(kernel_name); 246 247 CeedCall(CeedQFunctionGetCeed(qf, &ceed)); 248 249 CeedCall(CeedCheckFilePath(ceed, qf->user_source, &is_absolute_path)); 250 if (is_absolute_path) { 251 absolute_path = (char *)qf->user_source; 252 } else { 253 CeedCall(CeedGetJitAbsolutePath(ceed, qf->user_source, &absolute_path)); 254 } 255 256 size_t source_len = strlen(absolute_path) - kernel_name_len - 1; 257 CeedCall(CeedCalloc(source_len + 1, &source_path_copy)); 258 memcpy(source_path_copy, absolute_path, source_len); 259 qf->source_path = source_path_copy; 260 261 if (!is_absolute_path) CeedCall(CeedFree(&absolute_path)); 262 } 263 264 *source_path = (char *)qf->source_path; 265 return CEED_ERROR_SUCCESS; 266 } 267 268 /** 269 @brief Initialize and load QFunction source file into string buffer, including full text of local files in place of `#include "local.h"`. 270 The `buffer` is set to `NULL` if there is no QFunction source file. 271 Note: Caller is responsible for freeing the string buffer with `CeedFree()`. 272 273 @param[in] qf CeedQFunction 274 @param[out] source_buffer String buffer for source file contents 275 276 @return An error code: 0 - success, otherwise - failure 277 278 @ref Backend 279 **/ 280 int CeedQFunctionLoadSourceToBuffer(CeedQFunction qf, char **source_buffer) { 281 char *source_path; 282 283 CeedCall(CeedQFunctionGetSourcePath(qf, &source_path)); 284 *source_buffer = NULL; 285 if (source_path) { 286 CeedCall(CeedLoadSourceToBuffer(qf->ceed, source_path, source_buffer)); 287 } 288 289 return CEED_ERROR_SUCCESS; 290 } 291 292 /** 293 @brief Get the User Function for a CeedQFunction 294 295 @param[in] qf CeedQFunction 296 @param[out] f Variable to store user function 297 298 @return An error code: 0 - success, otherwise - failure 299 300 @ref Backend 301 **/ 302 int CeedQFunctionGetUserFunction(CeedQFunction qf, CeedQFunctionUser *f) { 303 *f = qf->function; 304 return CEED_ERROR_SUCCESS; 305 } 306 307 /** 308 @brief Get global context for a CeedQFunction. 309 Note: For QFunctions from the Fortran interface, this function will return the Fortran context CeedQFunctionContext. 310 311 @param[in] qf CeedQFunction 312 @param[out] ctx Variable to store CeedQFunctionContext 313 314 @return An error code: 0 - success, otherwise - failure 315 316 @ref Backend 317 **/ 318 int CeedQFunctionGetContext(CeedQFunction qf, CeedQFunctionContext *ctx) { 319 *ctx = qf->ctx; 320 return CEED_ERROR_SUCCESS; 321 } 322 323 /** 324 @brief Get context data of a CeedQFunction 325 326 @param[in] qf CeedQFunction 327 @param[in] mem_type Memory type on which to access the data. 328 If the backend uses a different memory type, this will perform a copy. 329 @param[out] data Data on memory type mem_type 330 331 @return An error code: 0 - success, otherwise - failure 332 333 @ref Backend 334 **/ 335 int CeedQFunctionGetContextData(CeedQFunction qf, CeedMemType mem_type, void *data) { 336 bool is_writable; 337 CeedQFunctionContext ctx; 338 339 CeedCall(CeedQFunctionGetContext(qf, &ctx)); 340 if (ctx) { 341 CeedCall(CeedQFunctionIsContextWritable(qf, &is_writable)); 342 if (is_writable) { 343 CeedCall(CeedQFunctionContextGetData(ctx, mem_type, data)); 344 } else { 345 CeedCall(CeedQFunctionContextGetDataRead(ctx, mem_type, data)); 346 } 347 } else { 348 *(void **)data = NULL; 349 } 350 return CEED_ERROR_SUCCESS; 351 } 352 353 /** 354 @brief Restore context data of a CeedQFunction 355 356 @param[in] qf CeedQFunction 357 @param[in,out] data Data to restore 358 359 @return An error code: 0 - success, otherwise - failure 360 361 @ref Backend 362 **/ 363 int CeedQFunctionRestoreContextData(CeedQFunction qf, void *data) { 364 bool is_writable; 365 CeedQFunctionContext ctx; 366 367 CeedCall(CeedQFunctionGetContext(qf, &ctx)); 368 if (ctx) { 369 CeedCall(CeedQFunctionIsContextWritable(qf, &is_writable)); 370 if (is_writable) { 371 CeedCall(CeedQFunctionContextRestoreData(ctx, data)); 372 } else { 373 CeedCall(CeedQFunctionContextRestoreDataRead(ctx, data)); 374 } 375 } 376 return CEED_ERROR_SUCCESS; 377 } 378 379 /** 380 @brief Get true user context for a CeedQFunction 381 Note: For all QFunctions this function will return the user CeedQFunctionContext and not interface context CeedQFunctionContext, if any 382 such object exists. 383 384 @param[in] qf CeedQFunction 385 @param[out] ctx Variable to store CeedQFunctionContext 386 387 @return An error code: 0 - success, otherwise - failure 388 @ref Backend 389 **/ 390 int CeedQFunctionGetInnerContext(CeedQFunction qf, CeedQFunctionContext *ctx) { 391 if (qf->is_fortran) { 392 CeedFortranContext fortran_ctx = NULL; 393 CeedCall(CeedQFunctionContextGetData(qf->ctx, CEED_MEM_HOST, &fortran_ctx)); 394 *ctx = fortran_ctx->inner_ctx; 395 CeedCall(CeedQFunctionContextRestoreData(qf->ctx, (void *)&fortran_ctx)); 396 } else { 397 *ctx = qf->ctx; 398 } 399 return CEED_ERROR_SUCCESS; 400 } 401 402 /** 403 @brief Get inner context data of a CeedQFunction 404 405 @param[in] qf CeedQFunction 406 @param[in] mem_type Memory type on which to access the data. 407 If the backend uses a different memory type, this will perform a copy. 408 @param[out] data Data on memory type mem_type 409 410 @return An error code: 0 - success, otherwise - failure 411 412 @ref Backend 413 **/ 414 int CeedQFunctionGetInnerContextData(CeedQFunction qf, CeedMemType mem_type, void *data) { 415 bool is_writable; 416 CeedQFunctionContext ctx; 417 418 CeedCall(CeedQFunctionGetInnerContext(qf, &ctx)); 419 if (ctx) { 420 CeedCall(CeedQFunctionIsContextWritable(qf, &is_writable)); 421 if (is_writable) { 422 CeedCall(CeedQFunctionContextGetData(ctx, mem_type, data)); 423 } else { 424 CeedCall(CeedQFunctionContextGetDataRead(ctx, mem_type, data)); 425 } 426 } else { 427 *(void **)data = NULL; 428 } 429 return CEED_ERROR_SUCCESS; 430 } 431 432 /** 433 @brief Restore inner context data of a CeedQFunction 434 435 @param[in] qf CeedQFunction 436 @param[in,out] data Data to restore 437 438 @return An error code: 0 - success, otherwise - failure 439 440 @ref Backend 441 **/ 442 int CeedQFunctionRestoreInnerContextData(CeedQFunction qf, void *data) { 443 bool is_writable; 444 CeedQFunctionContext ctx; 445 446 CeedCall(CeedQFunctionGetInnerContext(qf, &ctx)); 447 if (ctx) { 448 CeedCall(CeedQFunctionIsContextWritable(qf, &is_writable)); 449 if (is_writable) { 450 CeedCall(CeedQFunctionContextRestoreData(ctx, data)); 451 } else { 452 CeedCall(CeedQFunctionContextRestoreDataRead(ctx, data)); 453 } 454 } 455 return CEED_ERROR_SUCCESS; 456 } 457 458 /** 459 @brief Determine if QFunction is identity 460 461 @param[in] qf CeedQFunction 462 @param[out] is_identity Variable to store identity status 463 464 @return An error code: 0 - success, otherwise - failure 465 466 @ref Backend 467 **/ 468 int CeedQFunctionIsIdentity(CeedQFunction qf, bool *is_identity) { 469 *is_identity = qf->is_identity; 470 return CEED_ERROR_SUCCESS; 471 } 472 473 /** 474 @brief Determine if QFunctionContext is writable 475 476 @param[in] qf CeedQFunction 477 @param[out] is_writable Variable to store context writeable status 478 479 @return An error code: 0 - success, otherwise - failure 480 481 @ref Backend 482 **/ 483 int CeedQFunctionIsContextWritable(CeedQFunction qf, bool *is_writable) { 484 *is_writable = qf->is_context_writable; 485 return CEED_ERROR_SUCCESS; 486 } 487 488 /** 489 @brief Get backend data of a CeedQFunction 490 491 @param[in] qf CeedQFunction 492 @param[out] data Variable to store data 493 494 @return An error code: 0 - success, otherwise - failure 495 496 @ref Backend 497 **/ 498 int CeedQFunctionGetData(CeedQFunction qf, void *data) { 499 *(void **)data = qf->data; 500 return CEED_ERROR_SUCCESS; 501 } 502 503 /** 504 @brief Set backend data of a CeedQFunction 505 506 @param[in,out] qf CeedQFunction 507 @param[in] data Data to set 508 509 @return An error code: 0 - success, otherwise - failure 510 511 @ref Backend 512 **/ 513 int CeedQFunctionSetData(CeedQFunction qf, void *data) { 514 qf->data = data; 515 return CEED_ERROR_SUCCESS; 516 } 517 518 /** 519 @brief Increment the reference counter for a CeedQFunction 520 521 @param[in,out] qf CeedQFunction to increment the reference counter 522 523 @return An error code: 0 - success, otherwise - failure 524 525 @ref Backend 526 **/ 527 int CeedQFunctionReference(CeedQFunction qf) { 528 qf->ref_count++; 529 return CEED_ERROR_SUCCESS; 530 } 531 532 /** 533 @brief Estimate number of FLOPs per quadrature required to apply QFunction 534 535 @param[in] qf QFunction to estimate FLOPs for 536 @param[out] flops Address of variable to hold FLOPs estimate 537 538 @ref Backend 539 **/ 540 int CeedQFunctionGetFlopsEstimate(CeedQFunction qf, CeedSize *flops) { 541 if (qf->user_flop_estimate == -1) { 542 // LCOV_EXCL_START 543 return CeedError(qf->ceed, CEED_ERROR_INCOMPLETE, "Must set FLOPs estimate with CeedQFunctionSetUserFlopsEstimate"); 544 // LCOV_EXCL_STOP 545 } 546 *flops = qf->user_flop_estimate; 547 return CEED_ERROR_SUCCESS; 548 } 549 550 /// @} 551 552 /// ---------------------------------------------------------------------------- 553 /// CeedQFunction Public API 554 /// ---------------------------------------------------------------------------- 555 /// @addtogroup CeedQFunctionUser 556 /// @{ 557 558 /** 559 @brief Create a CeedQFunction for evaluating interior (volumetric) terms. 560 561 @param[in] ceed Ceed object where the CeedQFunction will be created 562 @param[in] vec_length Vector length. Caller must ensure that number of quadrature points is a multiple of vec_length. 563 @param[in] f Function pointer to evaluate action at quadrature points. 564 See \ref CeedQFunctionUser. 565 @param[in] source Absolute path to source of QFunction, "\abs_path\file.h:function_name". 566 For support across all backends, this source must only contain constructs supported by C99, C++11, and CUDA. 567 @param[out] qf Address of the variable where the newly created CeedQFunction will be stored 568 569 @return An error code: 0 - success, otherwise - failure 570 571 See \ref CeedQFunctionUser for details on the call-back function @a f's arguments. 572 573 @ref User 574 **/ 575 int CeedQFunctionCreateInterior(Ceed ceed, CeedInt vec_length, CeedQFunctionUser f, const char *source, CeedQFunction *qf) { 576 char *user_source_copy; 577 578 if (!ceed->QFunctionCreate) { 579 Ceed delegate; 580 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "QFunction")); 581 582 if (!delegate) { 583 // LCOV_EXCL_START 584 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support QFunctionCreate"); 585 // LCOV_EXCL_STOP 586 } 587 588 CeedCall(CeedQFunctionCreateInterior(delegate, vec_length, f, source, qf)); 589 return CEED_ERROR_SUCCESS; 590 } 591 592 if (strlen(source) && !strrchr(source, ':')) { 593 // LCOV_EXCL_START 594 return CeedError(ceed, CEED_ERROR_INCOMPLETE, 595 "Provided path to source does not include function name. Provided: \"%s\"\nRequired: \"\\abs_path\\file.h:function_name\"", 596 source); 597 // LCOV_EXCL_STOP 598 } 599 600 CeedCall(CeedCalloc(1, qf)); 601 (*qf)->ceed = ceed; 602 CeedCall(CeedReference(ceed)); 603 (*qf)->ref_count = 1; 604 (*qf)->vec_length = vec_length; 605 (*qf)->is_identity = false; 606 (*qf)->is_context_writable = true; 607 (*qf)->function = f; 608 (*qf)->user_flop_estimate = -1; 609 if (strlen(source)) { 610 size_t user_source_len = strlen(source); 611 612 CeedCall(CeedCalloc(user_source_len + 1, &user_source_copy)); 613 memcpy(user_source_copy, source, user_source_len); 614 (*qf)->user_source = user_source_copy; 615 } 616 CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*qf)->input_fields)); 617 CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*qf)->output_fields)); 618 CeedCall(ceed->QFunctionCreate(*qf)); 619 return CEED_ERROR_SUCCESS; 620 } 621 622 /** 623 @brief Create a CeedQFunction for evaluating interior (volumetric) terms by name. 624 625 @param[in] ceed Ceed object where the CeedQFunction will be created 626 @param[in] name Name of QFunction to use from gallery 627 @param[out] qf Address of the variable where the newly created CeedQFunction will be stored 628 629 @return An error code: 0 - success, otherwise - failure 630 631 @ref User 632 **/ 633 int CeedQFunctionCreateInteriorByName(Ceed ceed, const char *name, CeedQFunction *qf) { 634 size_t match_len = 0, match_index = UINT_MAX; 635 636 CeedCall(CeedQFunctionRegisterAll()); 637 // Find matching backend 638 if (!name) return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No QFunction name provided"); 639 for (size_t i = 0; i < num_qfunctions; i++) { 640 size_t n; 641 const char *curr_name = gallery_qfunctions[i].name; 642 for (n = 0; curr_name[n] && curr_name[n] == name[n]; n++) { 643 } 644 if (n > match_len) { 645 match_len = n; 646 match_index = i; 647 } 648 } 649 if (!match_len) { 650 // LCOV_EXCL_START 651 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "No suitable gallery QFunction"); 652 // LCOV_EXCL_STOP 653 } 654 655 // Create QFunction 656 CeedCall(CeedQFunctionCreateInterior(ceed, gallery_qfunctions[match_index].vec_length, gallery_qfunctions[match_index].f, 657 gallery_qfunctions[match_index].source, qf)); 658 659 // QFunction specific setup 660 CeedCall(gallery_qfunctions[match_index].init(ceed, name, *qf)); 661 662 // Copy name 663 CeedCall(CeedStringAllocCopy(name, (char **)&(*qf)->gallery_name)); 664 (*qf)->is_gallery = true; 665 return CEED_ERROR_SUCCESS; 666 } 667 668 /** 669 @brief Create an identity CeedQFunction. 670 Inputs are written into outputs in the order given. 671 This is useful for CeedOperators that can be represented with only the action of a CeedElemRestriction and CeedBasis, such as restriction 672 and prolongation operators for p-multigrid. Backends may optimize CeedOperators with this CeedQFunction to avoid the copy of input data to output 673 fields by using the same memory location for both. 674 675 @param[in] ceed Ceed object where the CeedQFunction will be created 676 @param[in] size Size of the QFunction fields 677 @param[in] in_mode CeedEvalMode for input to CeedQFunction 678 @param[in] out_mode CeedEvalMode for output to CeedQFunction 679 @param[out] qf Address of the variable where the newly created CeedQFunction will be stored 680 681 @return An error code: 0 - success, otherwise - failure 682 683 @ref User 684 **/ 685 int CeedQFunctionCreateIdentity(Ceed ceed, CeedInt size, CeedEvalMode in_mode, CeedEvalMode out_mode, CeedQFunction *qf) { 686 CeedCall(CeedQFunctionCreateInteriorByName(ceed, "Identity", qf)); 687 CeedCall(CeedQFunctionAddInput(*qf, "input", size, in_mode)); 688 CeedCall(CeedQFunctionAddOutput(*qf, "output", size, out_mode)); 689 690 (*qf)->is_identity = true; 691 692 CeedQFunctionContext ctx; 693 CeedContextFieldLabel size_label; 694 CeedCall(CeedQFunctionGetContext(*qf, &ctx)); 695 CeedCall(CeedQFunctionContextGetFieldLabel(ctx, "size", &size_label)); 696 CeedCall(CeedQFunctionContextSetInt32(ctx, size_label, &size)); 697 698 return CEED_ERROR_SUCCESS; 699 } 700 701 /** 702 @brief Copy the pointer to a CeedQFunction. 703 Both pointers should be destroyed with `CeedQFunctionDestroy()`. 704 705 Note: If the value of `qf_copy` passed to this function is non-NULL, then it is assumed that `*qf_copy` is a pointer to a CeedQFunction. 706 This CeedQFunction will be destroyed if `*qf_copy` is the only reference to this CeedQFunction. 707 708 @param[in] qf CeedQFunction to copy reference to 709 @param[out] qf_copy Variable to store copied reference 710 711 @return An error code: 0 - success, otherwise - failure 712 713 @ref User 714 **/ 715 int CeedQFunctionReferenceCopy(CeedQFunction qf, CeedQFunction *qf_copy) { 716 CeedCall(CeedQFunctionReference(qf)); 717 CeedCall(CeedQFunctionDestroy(qf_copy)); 718 *qf_copy = qf; 719 return CEED_ERROR_SUCCESS; 720 } 721 722 /** 723 @brief Add a CeedQFunction input 724 725 @param[in,out] qf CeedQFunction 726 @param[in] field_name Name of QFunction field 727 @param[in] size Size of QFunction field, (num_comp * dim) for @ref CEED_EVAL_GRAD or (num_comp * 1) for @ref CEED_EVAL_NONE and @ref 728 CEED_EVAL_INTERP 729 @param[in] eval_mode \ref CEED_EVAL_NONE to use values directly, 730 \ref CEED_EVAL_INTERP to use interpolated values, 731 \ref CEED_EVAL_GRAD to use gradients. 732 733 @return An error code: 0 - success, otherwise - failure 734 735 @ref User 736 **/ 737 int CeedQFunctionAddInput(CeedQFunction qf, const char *field_name, CeedInt size, CeedEvalMode eval_mode) { 738 if (qf->is_immutable) { 739 // LCOV_EXCL_START 740 return CeedError(qf->ceed, CEED_ERROR_MAJOR, "QFunction cannot be changed after set as immutable"); 741 // LCOV_EXCL_STOP 742 } 743 if ((eval_mode == CEED_EVAL_WEIGHT) && (size != 1)) { 744 // LCOV_EXCL_START 745 return CeedError(qf->ceed, CEED_ERROR_DIMENSION, "CEED_EVAL_WEIGHT should have size 1"); 746 // LCOV_EXCL_STOP 747 } 748 for (CeedInt i = 0; i < qf->num_input_fields; i++) { 749 if (!strcmp(field_name, qf->input_fields[i]->field_name)) { 750 // LCOV_EXCL_START 751 return CeedError(qf->ceed, CEED_ERROR_MINOR, "QFunction field names must be unique"); 752 // LCOV_EXCL_STOP 753 } 754 } 755 for (CeedInt i = 0; i < qf->num_output_fields; i++) { 756 if (!strcmp(field_name, qf->output_fields[i]->field_name)) { 757 // LCOV_EXCL_START 758 return CeedError(qf->ceed, CEED_ERROR_MINOR, "QFunction field names must be unique"); 759 // LCOV_EXCL_STOP 760 } 761 } 762 CeedCall(CeedQFunctionFieldSet(&qf->input_fields[qf->num_input_fields], field_name, size, eval_mode)); 763 qf->num_input_fields++; 764 return CEED_ERROR_SUCCESS; 765 } 766 767 /** 768 @brief Add a CeedQFunction output 769 770 @param[in,out] qf CeedQFunction 771 @param[in] field_name Name of QFunction field 772 @param[in] size Size of QFunction field, (num_comp * dim) for @ref CEED_EVAL_GRAD or (num_comp * 1) for @ref CEED_EVAL_NONE and @ref 773 CEED_EVAL_INTERP 774 @param[in] eval_mode \ref CEED_EVAL_NONE to use values directly, 775 \ref CEED_EVAL_INTERP to use interpolated values, 776 \ref CEED_EVAL_GRAD to use gradients. 777 778 @return An error code: 0 - success, otherwise - failure 779 780 @ref User 781 **/ 782 int CeedQFunctionAddOutput(CeedQFunction qf, const char *field_name, CeedInt size, CeedEvalMode eval_mode) { 783 if (qf->is_immutable) { 784 // LCOV_EXCL_START 785 return CeedError(qf->ceed, CEED_ERROR_MAJOR, "QFunction cannot be changed after set as immutable"); 786 // LCOV_EXCL_STOP 787 } 788 if (eval_mode == CEED_EVAL_WEIGHT) { 789 // LCOV_EXCL_START 790 return CeedError(qf->ceed, CEED_ERROR_DIMENSION, "Cannot create QFunction output with CEED_EVAL_WEIGHT"); 791 // LCOV_EXCL_STOP 792 } 793 for (CeedInt i = 0; i < qf->num_input_fields; i++) { 794 if (!strcmp(field_name, qf->input_fields[i]->field_name)) { 795 // LCOV_EXCL_START 796 return CeedError(qf->ceed, CEED_ERROR_MINOR, "QFunction field names must be unique"); 797 // LCOV_EXCL_STOP 798 } 799 } 800 for (CeedInt i = 0; i < qf->num_output_fields; i++) { 801 if (!strcmp(field_name, qf->output_fields[i]->field_name)) { 802 // LCOV_EXCL_START 803 return CeedError(qf->ceed, CEED_ERROR_MINOR, "QFunction field names must be unique"); 804 // LCOV_EXCL_STOP 805 } 806 } 807 CeedCall(CeedQFunctionFieldSet(&qf->output_fields[qf->num_output_fields], field_name, size, eval_mode)); 808 qf->num_output_fields++; 809 return CEED_ERROR_SUCCESS; 810 } 811 812 /** 813 @brief Get the CeedQFunctionFields of a CeedQFunction 814 815 Note: Calling this function asserts that setup is complete and sets the CeedQFunction as immutable. 816 817 @param[in] qf CeedQFunction 818 @param[out] num_input_fields Variable to store number of input fields 819 @param[out] input_fields Variable to store input fields 820 @param[out] num_output_fields Variable to store number of output fields 821 @param[out] output_fields Variable to store output fields 822 823 @return An error code: 0 - success, otherwise - failure 824 825 @ref Advanced 826 **/ 827 int CeedQFunctionGetFields(CeedQFunction qf, CeedInt *num_input_fields, CeedQFunctionField **input_fields, CeedInt *num_output_fields, 828 CeedQFunctionField **output_fields) { 829 qf->is_immutable = true; 830 if (num_input_fields) *num_input_fields = qf->num_input_fields; 831 if (input_fields) *input_fields = qf->input_fields; 832 if (num_output_fields) *num_output_fields = qf->num_output_fields; 833 if (output_fields) *output_fields = qf->output_fields; 834 return CEED_ERROR_SUCCESS; 835 } 836 837 /** 838 @brief Get the name of a CeedQFunctionField 839 840 @param[in] qf_field CeedQFunctionField 841 @param[out] field_name Variable to store the field name 842 843 @return An error code: 0 - success, otherwise - failure 844 845 @ref Advanced 846 **/ 847 int CeedQFunctionFieldGetName(CeedQFunctionField qf_field, char **field_name) { 848 *field_name = (char *)qf_field->field_name; 849 return CEED_ERROR_SUCCESS; 850 } 851 852 /** 853 @brief Get the number of components of a CeedQFunctionField 854 855 @param[in] qf_field CeedQFunctionField 856 @param[out] size Variable to store the size of the field 857 858 @return An error code: 0 - success, otherwise - failure 859 860 @ref Advanced 861 **/ 862 int CeedQFunctionFieldGetSize(CeedQFunctionField qf_field, CeedInt *size) { 863 *size = qf_field->size; 864 return CEED_ERROR_SUCCESS; 865 } 866 867 /** 868 @brief Get the CeedEvalMode of a CeedQFunctionField 869 870 @param[in] qf_field CeedQFunctionField 871 @param[out] eval_mode Variable to store the field evaluation mode 872 873 @return An error code: 0 - success, otherwise - failure 874 875 @ref Advanced 876 **/ 877 int CeedQFunctionFieldGetEvalMode(CeedQFunctionField qf_field, CeedEvalMode *eval_mode) { 878 *eval_mode = qf_field->eval_mode; 879 return CEED_ERROR_SUCCESS; 880 } 881 882 /** 883 @brief Set global context for a CeedQFunction 884 885 @param[in,out] qf CeedQFunction 886 @param[in] ctx Context data to set 887 888 @return An error code: 0 - success, otherwise - failure 889 890 @ref User 891 **/ 892 int CeedQFunctionSetContext(CeedQFunction qf, CeedQFunctionContext ctx) { 893 CeedCall(CeedQFunctionContextDestroy(&qf->ctx)); 894 qf->ctx = ctx; 895 if (ctx) { 896 CeedCall(CeedQFunctionContextReference(ctx)); 897 } 898 return CEED_ERROR_SUCCESS; 899 } 900 901 /** 902 @brief Set writability of CeedQFunctionContext when calling the `CeedQFunctionUser`. 903 The default value is `is_writable == true`. 904 905 Setting `is_writable == true` indicates the `CeedQFunctionUser` writes into the CeedQFunctionContextData and requires memory syncronization 906 after calling `CeedQFunctionApply()`. 907 908 Setting 'is_writable == false' asserts that `CeedQFunctionUser` does not modify the CeedQFunctionContextData. 909 Violating this assertion may lead to inconsistent data. 910 911 Setting `is_writable == false` may offer a performance improvement on GPU backends. 912 913 @param[in,out] qf CeedQFunction 914 @param[in] is_writable Writability status 915 916 @return An error code: 0 - success, otherwise - failure 917 918 @ref User 919 **/ 920 int CeedQFunctionSetContextWritable(CeedQFunction qf, bool is_writable) { 921 qf->is_context_writable = is_writable; 922 return CEED_ERROR_SUCCESS; 923 } 924 925 /** 926 @brief Set estimated number of FLOPs per quadrature required to apply QFunction 927 928 @param[in] qf QFunction to estimate FLOPs for 929 @param[out] flops FLOPs per quadrature point estimate 930 931 @ref Backend 932 **/ 933 int CeedQFunctionSetUserFlopsEstimate(CeedQFunction qf, CeedSize flops) { 934 if (flops < 0) { 935 // LCOV_EXCL_START 936 return CeedError(qf->ceed, CEED_ERROR_INCOMPATIBLE, "Must set non-negative FLOPs estimate"); 937 // LCOV_EXCL_STOP 938 } 939 qf->user_flop_estimate = flops; 940 return CEED_ERROR_SUCCESS; 941 } 942 943 /** 944 @brief View a CeedQFunction 945 946 @param[in] qf CeedQFunction to view 947 @param[in] stream Stream to write; typically stdout/stderr or a file 948 949 @return Error code: 0 - success, otherwise - failure 950 951 @ref User 952 **/ 953 int CeedQFunctionView(CeedQFunction qf, FILE *stream) { 954 char *kernel_name; 955 956 CeedCall(CeedQFunctionGetKernelName(qf, &kernel_name)); 957 fprintf(stream, "%sCeedQFunction - %s\n", qf->is_gallery ? "Gallery " : "User ", qf->is_gallery ? qf->gallery_name : kernel_name); 958 959 fprintf(stream, " %" CeedInt_FMT " input field%s:\n", qf->num_input_fields, qf->num_input_fields > 1 ? "s" : ""); 960 for (CeedInt i = 0; i < qf->num_input_fields; i++) { 961 CeedCall(CeedQFunctionFieldView(qf->input_fields[i], i, 1, stream)); 962 } 963 964 fprintf(stream, " %" CeedInt_FMT " output field%s:\n", qf->num_output_fields, qf->num_output_fields > 1 ? "s" : ""); 965 for (CeedInt i = 0; i < qf->num_output_fields; i++) { 966 CeedCall(CeedQFunctionFieldView(qf->output_fields[i], i, 0, stream)); 967 } 968 return CEED_ERROR_SUCCESS; 969 } 970 971 /** 972 @brief Get the Ceed associated with a CeedQFunction 973 974 @param[in] qf CeedQFunction 975 @param[out] ceed Variable to store Ceed 976 977 @return An error code: 0 - success, otherwise - failure 978 979 @ref Advanced 980 **/ 981 int CeedQFunctionGetCeed(CeedQFunction qf, Ceed *ceed) { 982 *ceed = qf->ceed; 983 return CEED_ERROR_SUCCESS; 984 } 985 986 /** 987 @brief Apply the action of a CeedQFunction 988 989 Note: Calling this function asserts that setup is complete and sets the CeedQFunction as immutable. 990 991 @param[in] qf CeedQFunction 992 @param[in] Q Number of quadrature points 993 @param[in] u Array of input CeedVectors 994 @param[out] v Array of output CeedVectors 995 996 @return An error code: 0 - success, otherwise - failure 997 998 @ref User 999 **/ 1000 int CeedQFunctionApply(CeedQFunction qf, CeedInt Q, CeedVector *u, CeedVector *v) { 1001 if (!qf->Apply) { 1002 // LCOV_EXCL_START 1003 return CeedError(qf->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support QFunctionApply"); 1004 // LCOV_EXCL_STOP 1005 } 1006 if (Q % qf->vec_length) { 1007 // LCOV_EXCL_START 1008 return CeedError(qf->ceed, CEED_ERROR_DIMENSION, "Number of quadrature points %" CeedInt_FMT " must be a multiple of %" CeedInt_FMT, Q, 1009 qf->vec_length); 1010 // LCOV_EXCL_STOP 1011 } 1012 qf->is_immutable = true; 1013 CeedCall(qf->Apply(qf, Q, u, v)); 1014 return CEED_ERROR_SUCCESS; 1015 } 1016 1017 /** 1018 @brief Destroy a CeedQFunction 1019 1020 @param[in,out] qf CeedQFunction to destroy 1021 1022 @return An error code: 0 - success, otherwise - failure 1023 1024 @ref User 1025 **/ 1026 int CeedQFunctionDestroy(CeedQFunction *qf) { 1027 if (!*qf || --(*qf)->ref_count > 0) { 1028 *qf = NULL; 1029 return CEED_ERROR_SUCCESS; 1030 } 1031 // Backend destroy 1032 if ((*qf)->Destroy) { 1033 CeedCall((*qf)->Destroy(*qf)); 1034 } 1035 // Free fields 1036 for (CeedInt i = 0; i < (*qf)->num_input_fields; i++) { 1037 CeedCall(CeedFree(&(*(*qf)->input_fields[i]).field_name)); 1038 CeedCall(CeedFree(&(*qf)->input_fields[i])); 1039 } 1040 for (CeedInt i = 0; i < (*qf)->num_output_fields; i++) { 1041 CeedCall(CeedFree(&(*(*qf)->output_fields[i]).field_name)); 1042 CeedCall(CeedFree(&(*qf)->output_fields[i])); 1043 } 1044 CeedCall(CeedFree(&(*qf)->input_fields)); 1045 CeedCall(CeedFree(&(*qf)->output_fields)); 1046 1047 // User context data object 1048 CeedCall(CeedQFunctionContextDestroy(&(*qf)->ctx)); 1049 1050 CeedCall(CeedFree(&(*qf)->user_source)); 1051 CeedCall(CeedFree(&(*qf)->source_path)); 1052 CeedCall(CeedFree(&(*qf)->gallery_name)); 1053 CeedCall(CeedFree(&(*qf)->kernel_name)); 1054 CeedCall(CeedDestroy(&(*qf)->ceed)); 1055 CeedCall(CeedFree(qf)); 1056 return CEED_ERROR_SUCCESS; 1057 } 1058 1059 /// @} 1060