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