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