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 CeedCheck(num_qfunctions < sizeof(gallery_qfunctions) / sizeof(gallery_qfunctions[0]), NULL, CEED_ERROR_MAJOR, "Too many gallery QFunctions"); 66 67 CeedDebugEnv("Gallery Register: %s", name); 68 69 const char *relative_file_path; 70 CeedCall(CeedGetJitRelativePath(source, &relative_file_path)); 71 72 strncpy(gallery_qfunctions[num_qfunctions].name, name, CEED_MAX_RESOURCE_LEN); 73 gallery_qfunctions[num_qfunctions].name[CEED_MAX_RESOURCE_LEN - 1] = 0; 74 strncpy(gallery_qfunctions[num_qfunctions].source, relative_file_path, CEED_MAX_RESOURCE_LEN); 75 gallery_qfunctions[num_qfunctions].source[CEED_MAX_RESOURCE_LEN - 1] = 0; 76 gallery_qfunctions[num_qfunctions].vec_length = vec_length; 77 gallery_qfunctions[num_qfunctions].f = f; 78 gallery_qfunctions[num_qfunctions].init = init; 79 num_qfunctions++; 80 return CEED_ERROR_SUCCESS; 81 } 82 83 /** 84 @brief Set a CeedQFunction field, used by CeedQFunctionAddInput/Output 85 86 @param[out] f CeedQFunctionField 87 @param[in] field_name Name of QFunction field 88 @param[in] size Size of QFunction field, (num_comp * 1) for @ref CEED_EVAL_NONE and @ref CEED_EVAL_WEIGHT, 89 (num_comp * 1) for @ref CEED_EVAL_INTERP for an H^1 space or (num_comp * dim) for an H(div) or H(curl) space, 90 (num_comp * dim) for @ref CEED_EVAL_GRAD, or (num_comp * 1) for @ref CEED_EVAL_DIV, and 91 (num_comp * curl_dim) with curl_dim = 1 if dim < 3 else dim for @ref CEED_EVAL_CURL. 92 @param[in] eval_mode \ref CEED_EVAL_NONE to use values directly, 93 \ref CEED_EVAL_WEIGHT to use quadrature weights, 94 \ref CEED_EVAL_INTERP to use interpolated values, 95 \ref CEED_EVAL_GRAD to use gradients, 96 \ref CEED_EVAL_DIV to use divergence, 97 \ref CEED_EVAL_CURL to use curl. 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 271 The `buffer` is set to `NULL` if there is no QFunction source file. 272 273 Note: Caller is responsible for freeing the string buffer with `CeedFree()`. 274 275 @param[in] qf CeedQFunction 276 @param[out] source_buffer String buffer for source file contents 277 278 @return An error code: 0 - success, otherwise - failure 279 280 @ref Backend 281 **/ 282 int CeedQFunctionLoadSourceToBuffer(CeedQFunction qf, char **source_buffer) { 283 char *source_path; 284 285 CeedCall(CeedQFunctionGetSourcePath(qf, &source_path)); 286 *source_buffer = NULL; 287 if (source_path) { 288 CeedCall(CeedLoadSourceToBuffer(qf->ceed, source_path, source_buffer)); 289 } 290 291 return CEED_ERROR_SUCCESS; 292 } 293 294 /** 295 @brief Get the User Function for a CeedQFunction 296 297 @param[in] qf CeedQFunction 298 @param[out] f Variable to store user function 299 300 @return An error code: 0 - success, otherwise - failure 301 302 @ref Backend 303 **/ 304 int CeedQFunctionGetUserFunction(CeedQFunction qf, CeedQFunctionUser *f) { 305 *f = qf->function; 306 return CEED_ERROR_SUCCESS; 307 } 308 309 /** 310 @brief Get global context for a CeedQFunction. 311 312 Note: For QFunctions from the Fortran interface, this function will return the Fortran context CeedQFunctionContext. 313 314 @param[in] qf CeedQFunction 315 @param[out] ctx Variable to store CeedQFunctionContext 316 317 @return An error code: 0 - success, otherwise - failure 318 319 @ref Backend 320 **/ 321 int CeedQFunctionGetContext(CeedQFunction qf, CeedQFunctionContext *ctx) { 322 *ctx = qf->ctx; 323 return CEED_ERROR_SUCCESS; 324 } 325 326 /** 327 @brief Get context data of a CeedQFunction 328 329 @param[in] qf CeedQFunction 330 @param[in] mem_type Memory type on which to access the data. 331 If the backend uses a different memory type, this will perform a copy. 332 @param[out] data Data on memory type mem_type 333 334 @return An error code: 0 - success, otherwise - failure 335 336 @ref Backend 337 **/ 338 int CeedQFunctionGetContextData(CeedQFunction qf, CeedMemType mem_type, void *data) { 339 bool is_writable; 340 CeedQFunctionContext ctx; 341 342 CeedCall(CeedQFunctionGetContext(qf, &ctx)); 343 if (ctx) { 344 CeedCall(CeedQFunctionIsContextWritable(qf, &is_writable)); 345 if (is_writable) { 346 CeedCall(CeedQFunctionContextGetData(ctx, mem_type, data)); 347 } else { 348 CeedCall(CeedQFunctionContextGetDataRead(ctx, mem_type, data)); 349 } 350 } else { 351 *(void **)data = NULL; 352 } 353 return CEED_ERROR_SUCCESS; 354 } 355 356 /** 357 @brief Restore context data of a CeedQFunction 358 359 @param[in] qf CeedQFunction 360 @param[in,out] data Data to restore 361 362 @return An error code: 0 - success, otherwise - failure 363 364 @ref Backend 365 **/ 366 int CeedQFunctionRestoreContextData(CeedQFunction qf, void *data) { 367 bool is_writable; 368 CeedQFunctionContext ctx; 369 370 CeedCall(CeedQFunctionGetContext(qf, &ctx)); 371 if (ctx) { 372 CeedCall(CeedQFunctionIsContextWritable(qf, &is_writable)); 373 if (is_writable) { 374 CeedCall(CeedQFunctionContextRestoreData(ctx, data)); 375 } else { 376 CeedCall(CeedQFunctionContextRestoreDataRead(ctx, data)); 377 } 378 } 379 return CEED_ERROR_SUCCESS; 380 } 381 382 /** 383 @brief Get true user context for a CeedQFunction 384 385 Note: For all QFunctions this function will return the user CeedQFunctionContext and not interface context CeedQFunctionContext, if any 386 such object exists. 387 388 @param[in] qf CeedQFunction 389 @param[out] ctx Variable to store CeedQFunctionContext 390 391 @return An error code: 0 - success, otherwise - failure 392 @ref Backend 393 **/ 394 int CeedQFunctionGetInnerContext(CeedQFunction qf, CeedQFunctionContext *ctx) { 395 if (qf->is_fortran) { 396 CeedFortranContext fortran_ctx = NULL; 397 CeedCall(CeedQFunctionContextGetData(qf->ctx, CEED_MEM_HOST, &fortran_ctx)); 398 *ctx = fortran_ctx->inner_ctx; 399 CeedCall(CeedQFunctionContextRestoreData(qf->ctx, (void *)&fortran_ctx)); 400 } else { 401 *ctx = qf->ctx; 402 } 403 return CEED_ERROR_SUCCESS; 404 } 405 406 /** 407 @brief Get inner context data of a CeedQFunction 408 409 @param[in] qf CeedQFunction 410 @param[in] mem_type Memory type on which to access the data. 411 If the backend uses a different memory type, this will perform a copy. 412 @param[out] data Data on memory type mem_type 413 414 @return An error code: 0 - success, otherwise - failure 415 416 @ref Backend 417 **/ 418 int CeedQFunctionGetInnerContextData(CeedQFunction qf, CeedMemType mem_type, void *data) { 419 bool is_writable; 420 CeedQFunctionContext ctx; 421 422 CeedCall(CeedQFunctionGetInnerContext(qf, &ctx)); 423 if (ctx) { 424 CeedCall(CeedQFunctionIsContextWritable(qf, &is_writable)); 425 if (is_writable) { 426 CeedCall(CeedQFunctionContextGetData(ctx, mem_type, data)); 427 } else { 428 CeedCall(CeedQFunctionContextGetDataRead(ctx, mem_type, data)); 429 } 430 } else { 431 *(void **)data = NULL; 432 } 433 return CEED_ERROR_SUCCESS; 434 } 435 436 /** 437 @brief Restore inner context data of a CeedQFunction 438 439 @param[in] qf CeedQFunction 440 @param[in,out] data Data to restore 441 442 @return An error code: 0 - success, otherwise - failure 443 444 @ref Backend 445 **/ 446 int CeedQFunctionRestoreInnerContextData(CeedQFunction qf, void *data) { 447 bool is_writable; 448 CeedQFunctionContext ctx; 449 450 CeedCall(CeedQFunctionGetInnerContext(qf, &ctx)); 451 if (ctx) { 452 CeedCall(CeedQFunctionIsContextWritable(qf, &is_writable)); 453 if (is_writable) { 454 CeedCall(CeedQFunctionContextRestoreData(ctx, data)); 455 } else { 456 CeedCall(CeedQFunctionContextRestoreDataRead(ctx, data)); 457 } 458 } 459 return CEED_ERROR_SUCCESS; 460 } 461 462 /** 463 @brief Determine if QFunction is identity 464 465 @param[in] qf CeedQFunction 466 @param[out] is_identity Variable to store identity status 467 468 @return An error code: 0 - success, otherwise - failure 469 470 @ref Backend 471 **/ 472 int CeedQFunctionIsIdentity(CeedQFunction qf, bool *is_identity) { 473 *is_identity = qf->is_identity; 474 return CEED_ERROR_SUCCESS; 475 } 476 477 /** 478 @brief Determine if QFunctionContext is writable 479 480 @param[in] qf CeedQFunction 481 @param[out] is_writable Variable to store context writeable status 482 483 @return An error code: 0 - success, otherwise - failure 484 485 @ref Backend 486 **/ 487 int CeedQFunctionIsContextWritable(CeedQFunction qf, bool *is_writable) { 488 *is_writable = qf->is_context_writable; 489 return CEED_ERROR_SUCCESS; 490 } 491 492 /** 493 @brief Get backend data of a CeedQFunction 494 495 @param[in] qf CeedQFunction 496 @param[out] data Variable to store data 497 498 @return An error code: 0 - success, otherwise - failure 499 500 @ref Backend 501 **/ 502 int CeedQFunctionGetData(CeedQFunction qf, void *data) { 503 *(void **)data = qf->data; 504 return CEED_ERROR_SUCCESS; 505 } 506 507 /** 508 @brief Set backend data of a CeedQFunction 509 510 @param[in,out] qf CeedQFunction 511 @param[in] data Data to set 512 513 @return An error code: 0 - success, otherwise - failure 514 515 @ref Backend 516 **/ 517 int CeedQFunctionSetData(CeedQFunction qf, void *data) { 518 qf->data = data; 519 return CEED_ERROR_SUCCESS; 520 } 521 522 /** 523 @brief Increment the reference counter for a CeedQFunction 524 525 @param[in,out] qf CeedQFunction to increment the reference counter 526 527 @return An error code: 0 - success, otherwise - failure 528 529 @ref Backend 530 **/ 531 int CeedQFunctionReference(CeedQFunction qf) { 532 qf->ref_count++; 533 return CEED_ERROR_SUCCESS; 534 } 535 536 /** 537 @brief Estimate number of FLOPs per quadrature required to apply QFunction 538 539 @param[in] qf QFunction to estimate FLOPs for 540 @param[out] flops Address of variable to hold FLOPs estimate 541 542 @ref Backend 543 **/ 544 int CeedQFunctionGetFlopsEstimate(CeedQFunction qf, CeedSize *flops) { 545 CeedCheck(qf->user_flop_estimate > -1, qf->ceed, CEED_ERROR_INCOMPLETE, "Must set FLOPs estimate with CeedQFunctionSetUserFlopsEstimate"); 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 581 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "QFunction")); 582 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support QFunctionCreate"); 583 CeedCall(CeedQFunctionCreateInterior(delegate, vec_length, f, source, qf)); 584 return CEED_ERROR_SUCCESS; 585 } 586 587 CeedCheck(!strlen(source) || strrchr(source, ':'), ceed, CEED_ERROR_INCOMPLETE, 588 "Provided path to source does not include function name. Provided: \"%s\"\nRequired: \"\\abs_path\\file.h:function_name\"", source); 589 590 CeedCall(CeedCalloc(1, qf)); 591 (*qf)->ceed = ceed; 592 CeedCall(CeedReference(ceed)); 593 (*qf)->ref_count = 1; 594 (*qf)->vec_length = vec_length; 595 (*qf)->is_identity = false; 596 (*qf)->is_context_writable = true; 597 (*qf)->function = f; 598 (*qf)->user_flop_estimate = -1; 599 if (strlen(source)) { 600 size_t user_source_len = strlen(source); 601 602 CeedCall(CeedCalloc(user_source_len + 1, &user_source_copy)); 603 memcpy(user_source_copy, source, user_source_len); 604 (*qf)->user_source = user_source_copy; 605 } 606 CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*qf)->input_fields)); 607 CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*qf)->output_fields)); 608 CeedCall(ceed->QFunctionCreate(*qf)); 609 return CEED_ERROR_SUCCESS; 610 } 611 612 /** 613 @brief Create a CeedQFunction for evaluating interior (volumetric) terms by name. 614 615 @param[in] ceed Ceed object where the CeedQFunction will be created 616 @param[in] name Name of QFunction to use from gallery 617 @param[out] qf Address of the variable where the newly created CeedQFunction will be stored 618 619 @return An error code: 0 - success, otherwise - failure 620 621 @ref User 622 **/ 623 int CeedQFunctionCreateInteriorByName(Ceed ceed, const char *name, CeedQFunction *qf) { 624 size_t match_len = 0, match_index = UINT_MAX; 625 626 CeedCall(CeedQFunctionRegisterAll()); 627 // Find matching backend 628 CeedCheck(name, ceed, CEED_ERROR_INCOMPLETE, "No QFunction name provided"); 629 for (size_t i = 0; i < num_qfunctions; i++) { 630 size_t n; 631 const char *curr_name = gallery_qfunctions[i].name; 632 for (n = 0; curr_name[n] && curr_name[n] == name[n]; n++) { 633 } 634 if (n > match_len) { 635 match_len = n; 636 match_index = i; 637 } 638 } 639 CeedCheck(match_len > 0, ceed, CEED_ERROR_UNSUPPORTED, "No suitable gallery QFunction"); 640 641 // Create QFunction 642 CeedCall(CeedQFunctionCreateInterior(ceed, gallery_qfunctions[match_index].vec_length, gallery_qfunctions[match_index].f, 643 gallery_qfunctions[match_index].source, qf)); 644 645 // QFunction specific setup 646 CeedCall(gallery_qfunctions[match_index].init(ceed, name, *qf)); 647 648 // Copy name 649 CeedCall(CeedStringAllocCopy(name, (char **)&(*qf)->gallery_name)); 650 (*qf)->is_gallery = true; 651 return CEED_ERROR_SUCCESS; 652 } 653 654 /** 655 @brief Create an identity CeedQFunction. 656 657 Inputs are written into outputs in the order given. 658 This is useful for CeedOperators that can be represented with only the action of a CeedElemRestriction and CeedBasis, such as restriction 659 and prolongation operators for p-multigrid. 660 Backends may optimize CeedOperators with this CeedQFunction to avoid the copy of input data to output fields by using the same memory location for 661 both. 662 663 @param[in] ceed Ceed object where the CeedQFunction will be created 664 @param[in] size Size of the QFunction fields 665 @param[in] in_mode CeedEvalMode for input to CeedQFunction 666 @param[in] out_mode CeedEvalMode for output to CeedQFunction 667 @param[out] qf Address of the variable where the newly created CeedQFunction will be stored 668 669 @return An error code: 0 - success, otherwise - failure 670 671 @ref User 672 **/ 673 int CeedQFunctionCreateIdentity(Ceed ceed, CeedInt size, CeedEvalMode in_mode, CeedEvalMode out_mode, CeedQFunction *qf) { 674 CeedCall(CeedQFunctionCreateInteriorByName(ceed, "Identity", qf)); 675 CeedCall(CeedQFunctionAddInput(*qf, "input", size, in_mode)); 676 CeedCall(CeedQFunctionAddOutput(*qf, "output", size, out_mode)); 677 678 (*qf)->is_identity = true; 679 680 CeedQFunctionContext ctx; 681 CeedContextFieldLabel size_label; 682 CeedCall(CeedQFunctionGetContext(*qf, &ctx)); 683 CeedCall(CeedQFunctionContextGetFieldLabel(ctx, "size", &size_label)); 684 CeedCall(CeedQFunctionContextSetInt32(ctx, size_label, &size)); 685 686 return CEED_ERROR_SUCCESS; 687 } 688 689 /** 690 @brief Copy the pointer to a CeedQFunction. 691 692 Both pointers should be destroyed with `CeedQFunctionDestroy()`. 693 694 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. 695 This CeedQFunction will be destroyed if `*qf_copy` is the only reference to this CeedQFunction. 696 697 @param[in] qf CeedQFunction to copy reference to 698 @param[out] qf_copy Variable to store copied reference 699 700 @return An error code: 0 - success, otherwise - failure 701 702 @ref User 703 **/ 704 int CeedQFunctionReferenceCopy(CeedQFunction qf, CeedQFunction *qf_copy) { 705 CeedCall(CeedQFunctionReference(qf)); 706 CeedCall(CeedQFunctionDestroy(qf_copy)); 707 *qf_copy = qf; 708 return CEED_ERROR_SUCCESS; 709 } 710 711 /** 712 @brief Add a CeedQFunction input 713 714 @param[in,out] qf CeedQFunction 715 @param[in] field_name Name of QFunction field 716 @param[in] size Size of QFunction field, (num_comp * 1) for @ref CEED_EVAL_NONE, 717 (num_comp * 1) for @ref CEED_EVAL_INTERP for an H^1 space or (num_comp * dim) for an H(div) or H(curl) space, 718 (num_comp * dim) for @ref CEED_EVAL_GRAD, or (num_comp * 1) for @ref CEED_EVAL_DIV, and 719 (num_comp * curl_dim) with curl_dim = 1 if dim < 3 else dim for @ref CEED_EVAL_CURL. 720 @param[in] eval_mode \ref CEED_EVAL_NONE to use values directly, 721 \ref CEED_EVAL_INTERP to use interpolated values, 722 \ref CEED_EVAL_GRAD to use gradients, 723 \ref CEED_EVAL_DIV to use divergence, 724 \ref CEED_EVAL_CURL to use curl. 725 726 @return An error code: 0 - success, otherwise - failure 727 728 @ref User 729 **/ 730 int CeedQFunctionAddInput(CeedQFunction qf, const char *field_name, CeedInt size, CeedEvalMode eval_mode) { 731 CeedCheck(!qf->is_immutable, qf->ceed, CEED_ERROR_MAJOR, "QFunction cannot be changed after set as immutable"); 732 CeedCheck(eval_mode != CEED_EVAL_WEIGHT || size == 1, qf->ceed, CEED_ERROR_DIMENSION, "CEED_EVAL_WEIGHT should have size 1"); 733 for (CeedInt i = 0; i < qf->num_input_fields; i++) { 734 CeedCheck(strcmp(field_name, qf->input_fields[i]->field_name), qf->ceed, CEED_ERROR_MINOR, "QFunction field names must be unique"); 735 } 736 for (CeedInt i = 0; i < qf->num_output_fields; i++) { 737 CeedCheck(strcmp(field_name, qf->output_fields[i]->field_name), qf->ceed, CEED_ERROR_MINOR, "QFunction field names must be unique"); 738 } 739 CeedCall(CeedQFunctionFieldSet(&qf->input_fields[qf->num_input_fields], field_name, size, eval_mode)); 740 qf->num_input_fields++; 741 return CEED_ERROR_SUCCESS; 742 } 743 744 /** 745 @brief Add a CeedQFunction output 746 747 @param[in,out] qf CeedQFunction 748 @param[in] field_name Name of QFunction field 749 @param[in] size Size of QFunction field, (num_comp * 1) for @ref CEED_EVAL_NONE, 750 (num_comp * 1) for @ref CEED_EVAL_INTERP for an H^1 space or (num_comp * dim) for an H(div) or H(curl) space, 751 (num_comp * dim) for @ref CEED_EVAL_GRAD, or (num_comp * 1) for @ref CEED_EVAL_DIV, and 752 (num_comp * curl_dim) with curl_dim = 1 if dim < 3 else dim for @ref CEED_EVAL_CURL. 753 @param[in] eval_mode \ref CEED_EVAL_NONE to use values directly, 754 \ref CEED_EVAL_INTERP to use interpolated values, 755 \ref CEED_EVAL_GRAD to use gradients, 756 \ref CEED_EVAL_DIV to use divergence, 757 \ref CEED_EVAL_CURL to use curl. 758 759 @return An error code: 0 - success, otherwise - failure 760 761 @ref User 762 **/ 763 int CeedQFunctionAddOutput(CeedQFunction qf, const char *field_name, CeedInt size, CeedEvalMode eval_mode) { 764 CeedCheck(!qf->is_immutable, qf->ceed, CEED_ERROR_MAJOR, "QFunction cannot be changed after set as immutable"); 765 CeedCheck(eval_mode != CEED_EVAL_WEIGHT, qf->ceed, CEED_ERROR_DIMENSION, "Cannot create QFunction output with CEED_EVAL_WEIGHT"); 766 for (CeedInt i = 0; i < qf->num_input_fields; i++) { 767 CeedCheck(strcmp(field_name, qf->input_fields[i]->field_name), qf->ceed, CEED_ERROR_MINOR, "QFunction field names must be unique"); 768 } 769 for (CeedInt i = 0; i < qf->num_output_fields; i++) { 770 CeedCheck(strcmp(field_name, qf->output_fields[i]->field_name), qf->ceed, CEED_ERROR_MINOR, "QFunction field names must be unique"); 771 } 772 CeedCall(CeedQFunctionFieldSet(&qf->output_fields[qf->num_output_fields], field_name, size, eval_mode)); 773 qf->num_output_fields++; 774 return CEED_ERROR_SUCCESS; 775 } 776 777 /** 778 @brief Get the CeedQFunctionFields of a CeedQFunction 779 780 Note: Calling this function asserts that setup is complete and sets the CeedQFunction as immutable. 781 782 @param[in] qf CeedQFunction 783 @param[out] num_input_fields Variable to store number of input fields 784 @param[out] input_fields Variable to store input fields 785 @param[out] num_output_fields Variable to store number of output fields 786 @param[out] output_fields Variable to store output fields 787 788 @return An error code: 0 - success, otherwise - failure 789 790 @ref Advanced 791 **/ 792 int CeedQFunctionGetFields(CeedQFunction qf, CeedInt *num_input_fields, CeedQFunctionField **input_fields, CeedInt *num_output_fields, 793 CeedQFunctionField **output_fields) { 794 qf->is_immutable = true; 795 if (num_input_fields) *num_input_fields = qf->num_input_fields; 796 if (input_fields) *input_fields = qf->input_fields; 797 if (num_output_fields) *num_output_fields = qf->num_output_fields; 798 if (output_fields) *output_fields = qf->output_fields; 799 return CEED_ERROR_SUCCESS; 800 } 801 802 /** 803 @brief Get the name of a CeedQFunctionField 804 805 @param[in] qf_field CeedQFunctionField 806 @param[out] field_name Variable to store the field name 807 808 @return An error code: 0 - success, otherwise - failure 809 810 @ref Advanced 811 **/ 812 int CeedQFunctionFieldGetName(CeedQFunctionField qf_field, char **field_name) { 813 *field_name = (char *)qf_field->field_name; 814 return CEED_ERROR_SUCCESS; 815 } 816 817 /** 818 @brief Get the number of components of a CeedQFunctionField 819 820 @param[in] qf_field CeedQFunctionField 821 @param[out] size Variable to store the size of the field 822 823 @return An error code: 0 - success, otherwise - failure 824 825 @ref Advanced 826 **/ 827 int CeedQFunctionFieldGetSize(CeedQFunctionField qf_field, CeedInt *size) { 828 *size = qf_field->size; 829 return CEED_ERROR_SUCCESS; 830 } 831 832 /** 833 @brief Get the CeedEvalMode of a CeedQFunctionField 834 835 @param[in] qf_field CeedQFunctionField 836 @param[out] eval_mode Variable to store the field evaluation mode 837 838 @return An error code: 0 - success, otherwise - failure 839 840 @ref Advanced 841 **/ 842 int CeedQFunctionFieldGetEvalMode(CeedQFunctionField qf_field, CeedEvalMode *eval_mode) { 843 *eval_mode = qf_field->eval_mode; 844 return CEED_ERROR_SUCCESS; 845 } 846 847 /** 848 @brief Set global context for a CeedQFunction 849 850 @param[in,out] qf CeedQFunction 851 @param[in] ctx Context data to set 852 853 @return An error code: 0 - success, otherwise - failure 854 855 @ref User 856 **/ 857 int CeedQFunctionSetContext(CeedQFunction qf, CeedQFunctionContext ctx) { 858 CeedCall(CeedQFunctionContextDestroy(&qf->ctx)); 859 qf->ctx = ctx; 860 if (ctx) { 861 CeedCall(CeedQFunctionContextReference(ctx)); 862 } 863 return CEED_ERROR_SUCCESS; 864 } 865 866 /** 867 @brief Set writability of CeedQFunctionContext when calling the `CeedQFunctionUser`. 868 869 The default value is `is_writable == true`. 870 871 Setting `is_writable == true` indicates the `CeedQFunctionUser` writes into the CeedQFunctionContextData and requires memory syncronization 872 after calling `CeedQFunctionApply()`. 873 874 Setting 'is_writable == false' asserts that `CeedQFunctionUser` does not modify the CeedQFunctionContextData. 875 Violating this assertion may lead to inconsistent data. 876 877 Setting `is_writable == false` may offer a performance improvement on GPU backends. 878 879 @param[in,out] qf CeedQFunction 880 @param[in] is_writable Writability status 881 882 @return An error code: 0 - success, otherwise - failure 883 884 @ref User 885 **/ 886 int CeedQFunctionSetContextWritable(CeedQFunction qf, bool is_writable) { 887 qf->is_context_writable = is_writable; 888 return CEED_ERROR_SUCCESS; 889 } 890 891 /** 892 @brief Set estimated number of FLOPs per quadrature required to apply QFunction 893 894 @param[in] qf QFunction to estimate FLOPs for 895 @param[out] flops FLOPs per quadrature point estimate 896 897 @ref Backend 898 **/ 899 int CeedQFunctionSetUserFlopsEstimate(CeedQFunction qf, CeedSize flops) { 900 CeedCheck(flops >= 0, qf->ceed, CEED_ERROR_INCOMPATIBLE, "Must set non-negative FLOPs estimate"); 901 qf->user_flop_estimate = flops; 902 return CEED_ERROR_SUCCESS; 903 } 904 905 /** 906 @brief View a CeedQFunction 907 908 @param[in] qf CeedQFunction to view 909 @param[in] stream Stream to write; typically stdout/stderr or a file 910 911 @return Error code: 0 - success, otherwise - failure 912 913 @ref User 914 **/ 915 int CeedQFunctionView(CeedQFunction qf, FILE *stream) { 916 char *kernel_name; 917 918 CeedCall(CeedQFunctionGetKernelName(qf, &kernel_name)); 919 fprintf(stream, "%sCeedQFunction - %s\n", qf->is_gallery ? "Gallery " : "User ", qf->is_gallery ? qf->gallery_name : kernel_name); 920 921 fprintf(stream, " %" CeedInt_FMT " input field%s:\n", qf->num_input_fields, qf->num_input_fields > 1 ? "s" : ""); 922 for (CeedInt i = 0; i < qf->num_input_fields; i++) { 923 CeedCall(CeedQFunctionFieldView(qf->input_fields[i], i, 1, stream)); 924 } 925 926 fprintf(stream, " %" CeedInt_FMT " output field%s:\n", qf->num_output_fields, qf->num_output_fields > 1 ? "s" : ""); 927 for (CeedInt i = 0; i < qf->num_output_fields; i++) { 928 CeedCall(CeedQFunctionFieldView(qf->output_fields[i], i, 0, stream)); 929 } 930 return CEED_ERROR_SUCCESS; 931 } 932 933 /** 934 @brief Get the Ceed associated with a CeedQFunction 935 936 @param[in] qf CeedQFunction 937 @param[out] ceed Variable to store Ceed 938 939 @return An error code: 0 - success, otherwise - failure 940 941 @ref Advanced 942 **/ 943 int CeedQFunctionGetCeed(CeedQFunction qf, Ceed *ceed) { 944 *ceed = qf->ceed; 945 return CEED_ERROR_SUCCESS; 946 } 947 948 /** 949 @brief Apply the action of a CeedQFunction 950 951 Note: Calling this function asserts that setup is complete and sets the CeedQFunction as immutable. 952 953 @param[in] qf CeedQFunction 954 @param[in] Q Number of quadrature points 955 @param[in] u Array of input CeedVectors 956 @param[out] v Array of output CeedVectors 957 958 @return An error code: 0 - success, otherwise - failure 959 960 @ref User 961 **/ 962 int CeedQFunctionApply(CeedQFunction qf, CeedInt Q, CeedVector *u, CeedVector *v) { 963 CeedCheck(qf->Apply, qf->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support QFunctionApply"); 964 CeedCheck(Q % qf->vec_length == 0, qf->ceed, CEED_ERROR_DIMENSION, 965 "Number of quadrature points %" CeedInt_FMT " must be a multiple of %" CeedInt_FMT, Q, qf->vec_length); 966 qf->is_immutable = true; 967 CeedCall(qf->Apply(qf, Q, u, v)); 968 return CEED_ERROR_SUCCESS; 969 } 970 971 /** 972 @brief Destroy a CeedQFunction 973 974 @param[in,out] qf CeedQFunction to destroy 975 976 @return An error code: 0 - success, otherwise - failure 977 978 @ref User 979 **/ 980 int CeedQFunctionDestroy(CeedQFunction *qf) { 981 if (!*qf || --(*qf)->ref_count > 0) { 982 *qf = NULL; 983 return CEED_ERROR_SUCCESS; 984 } 985 // Backend destroy 986 if ((*qf)->Destroy) { 987 CeedCall((*qf)->Destroy(*qf)); 988 } 989 // Free fields 990 for (CeedInt i = 0; i < (*qf)->num_input_fields; i++) { 991 CeedCall(CeedFree(&(*(*qf)->input_fields[i]).field_name)); 992 CeedCall(CeedFree(&(*qf)->input_fields[i])); 993 } 994 for (CeedInt i = 0; i < (*qf)->num_output_fields; i++) { 995 CeedCall(CeedFree(&(*(*qf)->output_fields[i]).field_name)); 996 CeedCall(CeedFree(&(*qf)->output_fields[i])); 997 } 998 CeedCall(CeedFree(&(*qf)->input_fields)); 999 CeedCall(CeedFree(&(*qf)->output_fields)); 1000 1001 // User context data object 1002 CeedCall(CeedQFunctionContextDestroy(&(*qf)->ctx)); 1003 1004 CeedCall(CeedFree(&(*qf)->user_source)); 1005 CeedCall(CeedFree(&(*qf)->source_path)); 1006 CeedCall(CeedFree(&(*qf)->gallery_name)); 1007 CeedCall(CeedFree(&(*qf)->kernel_name)); 1008 CeedCall(CeedDestroy(&(*qf)->ceed)); 1009 CeedCall(CeedFree(qf)); 1010 return CEED_ERROR_SUCCESS; 1011 } 1012 1013 /// @} 1014