diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index e57889c82f..40c498aef7 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -23,3 +23,4 @@ detail. Why is this change required? What problem does it solve?--> If preparing for a new release, in addition please check the following: - [ ] Update the version in cmake. - [ ] Move the changes in the CHANGELOG.md file under a new header for the new release, and reset the categories. +- [ ] Ensure that any `when='@main'` dependencies are updated to the release version in the package.py diff --git a/.github/workflows/draft-pdf.yml b/.github/workflows/draft-pdf.yml new file mode 100644 index 0000000000..ceeed6452a --- /dev/null +++ b/.github/workflows/draft-pdf.yml @@ -0,0 +1,32 @@ +name: Generate JOSS paper + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + release: + types: + - created + +jobs: + paper: + runs-on: ubuntu-latest + name: Paper Draft + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Build draft PDF + uses: openjournals/openjournals-draft-action@master + with: + journal: joss + # This should be the path to the paper within your repo. + paper-path: joss-paper/paper.md + - name: Upload + uses: actions/upload-artifact@v1 + with: + name: paper + # This is the output path where Pandoc will write the compiled + # PDF. Note, this should be the same directory as the input + # paper.md + path: joss-paper/paper.pdf diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 47090631f5..2d3780b7a2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -38,6 +38,7 @@ jobs: -DSINGULARITY_USE_HELMHOLTZ=ON \ -DSINGULARITY_TEST_HELMHOLTZ=ON \ -DSINGULARITY_FORCE_SUBMODULE_MODE=ON \ + -DSINGULARITY_PLUGINS=$(pwd)/../example/plugin \ .. #-DSINGULARITY_TEST_PYTHON=ON \ #-DSINGULARITY_TEST_STELLAR_COLLAPSE=ON \ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 45a71a02c1..13a62cf46e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,45 +3,43 @@ ################### stages: + - prepare - build_n_test variables: - GIT_SUBMODULE_STRATEGY: recursive - SINGULARITY_EOS_GCC_VERSION: "9.3.0" - SINGULARITY_EOS_OPENMPI_VERSION: "4.1.3" + GIT_SUBMODULE_STRATEGY: normal + XCAP_PROJECT_DIR: "/usr/projects/xcap/oss" + TESTING_CLUSTER: darwin + SINGULARITY_GOLDFILES_VERSION: "goldfiles-1.8.0" + SINGULARITY_EOS_GCC_VERSION: "10.3.0" + SINGULARITY_EOS_OPENMPI_VERSION: "4.1.1" SINGULARITY_EOS_CUDA_VERSION: "11.6.0" SINGULARITY_EOS_BUILD_TYPE: "RelWithDebInfo" - SINGULARITY_EOS_SPACK_SPEC: "singularity-eos@main+mpi+hdf5+python+tests%gcc@${SINGULARITY_EOS_GCC_VERSION} ^openmpi@${SINGULARITY_EOS_OPENMPI_VERSION}" + SINGULARITY_EOS_CXX_STANDARD: 14 + SINGULARITY_EOS_SPACK_SPEC: "singularity-eos@main+mpi+spiner+hdf5+python+tests%gcc@=${SINGULARITY_EOS_GCC_VERSION} ^openmpi@${SINGULARITY_EOS_OPENMPI_VERSION}" COLOR_CYAN: "\e[1;36m" COLOR_PLAIN: "\e[0m" - # set to different spack upstream for testing - SINGULARITY_EOS_TEMP_SPACK_DIR: "" - # uncomment for debugging the CI and persist the Spack installation - # SPACK_USER_CACHE_PATH: "${CI_PROJECT_DIR}/spack-local" - # DEVEL_SPACK_CHECKOUT: "${CI_PROJECT_DIR}/spack" - -before_script: - - echo "Running on $(hostname)" - - section() { echo $'\e[0K'"section_$1:$(date +%s):$2"$'\r\e[0K'"${3+${COLOR_CYAN}$3${COLOR_PLAIN}}"; } - - export PYTHONNOUSERSITE=1 - - export SPACK_DISABLE_LOCAL_CONFIG=true - - export SPACK_USER_CACHE_PATH=${SPACK_USER_CACHE_PATH:-/tmp/spack-local} - - export DEVEL_SPACK_CHECKOUT=${DEVEL_SPACK_CHECKOUT:-/tmp/spack} - - export SINGULARITY_EOS_SPACK_DIR=${SINGULARITY_EOS_TEMP_SPACK_DIR:=$XCAP_OSS_SPACK_DIR} - - section start "spack_init[collapsed=true]" "Creating Spack instance at ${DEVEL_SPACK_CHECKOUT}" - - | - rsync -rpl \ - --exclude=".git" \ - --exclude="etc/spack/repos.yaml" \ - --exclude="etc/spack/packages.yaml" \ - --include="etc/spack/**" \ - --include="lib/spack/**" \ - --exclude-from=${SINGULARITY_EOS_SPACK_DIR}/.gitignore \ - ${SINGULARITY_EOS_SPACK_DIR}/ ${DEVEL_SPACK_CHECKOUT}/ - - source ${DEVEL_SPACK_CHECKOUT}/share/spack/setup-env.sh - - spack --version - - spack compiler list - - section end spack_init + # uncomment to have the CI Spack installation for debugging + # PROJECT_TMP_CI_DIR: "${CI_PROJECT_DIR}" + # uncomment & set to different spack upstream for testing + # PROJECT_TMP_SPACK_DIR: "deployment/CI/spack-v0.20.1-8" + # uncomment for spack debug output + # PROJECT_SPACK_DEBUG_FLAG: "-d" + +workflow: + rules: + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + - if: $CI_PIPELINE_SOURCE == "pipeline" + - if: $CI_PIPELINE_SOURCE == "schedule" + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH + - if: $CI_COMMIT_TAG + +default: + tags: + - darwin-slurm-shared + id_tokens: + SITE_ID_TOKEN: + aud: https://asc-git.lanl.gov ########################## # Build Matrix Variables # @@ -58,7 +56,7 @@ before_script: .gpu: &gpu SINGULARITY_USE_CUDA: "true" - SINGULARITY_EOS_SPACK_SPEC: "singularity-eos@main+mpi+tests+cuda+kokkos+hdf5 cuda_arch=70 +kokkos-kernels%gcc@${SINGULARITY_EOS_GCC_VERSION} ^cuda@${SINGULARITY_EOS_CUDA_VERSION} ^openmpi@${SINGULARITY_EOS_OPENMPI_VERSION}" + SINGULARITY_EOS_SPACK_SPEC: "singularity-eos@main+mpi+tests+cuda+kokkos+spiner+hdf5 cuda_arch=${SINGULARITY_CUDA_ARCH} +kokkos-kernels%gcc@=${SINGULARITY_EOS_GCC_VERSION} ^kokkos std=14 ^cuda@${SINGULARITY_EOS_CUDA_VERSION} ^openmpi@${SINGULARITY_EOS_OPENMPI_VERSION}" .fort: &fort SINGULARITY_USE_FORTRAN: "true" @@ -66,67 +64,122 @@ before_script: .nofort: &nofort SINGULARITY_USE_FORTRAN: "false" -.skylake: &skylake - SCHEDULER_PARAMETERS: "--nodes=1 --partition=skylake-gold,skylake-platinum" - -.power9: &power9 - SCHEDULER_PARAMETERS: "--nodes=1 --partition=power9-rhel7" - -.x86volta: &x86volta - SCHEDULER_PARAMETERS: "--nodes=1 --partition=volta-x86 -C cpu_family:haswell" - .python: &python SINGULARITY_BUILD_PYTHON: "ON" -################# -# General Setup # -################# +###################### +# Platform Variables # +###################### -.job: &job_def - id_tokens: - SITE_ID_TOKEN: - aud: https://asc-git.lanl.gov +.rocinante_shell: tags: - - darwin-slurm-shared + - rocinante + - shell + +.rocinante_batch: + tags: + - rocinante + - batch variables: - SCHEDULER_PARAMETERS: "--nodes=1 --partition=skylake-gold,skylake-platinum" - only: - refs: - - main - - merge_requests - except: - refs: + TESTING_CLUSTER: rocinante + SINGULARITY_EOS_GCC_VERSION: "12.2.0" + SINGULARITY_EOS_SPACK_SPEC: "singularity-eos@main+mpi+spiner+hdf5+python+tests%gcc@=${SINGULARITY_EOS_GCC_VERSION} ^cray-mpich" + SCHEDULER_PARAMETERS: "--nodes=1 --time 2:00:00 -L none@slurmdb --account=asc-ci --qos=ci --reservation=ci --partition=ci" + HDF5_USE_FILE_LOCKING: "FALSE" + +.skylake: &skylake + SCHEDULER_PARAMETERS: "--nodes=1 -p skylake-gold,skylake-platinum" + +.x86volta: &x86volta + SINGULARITY_CUDA_ARCH: 70 + SCHEDULER_PARAMETERS: "--nodes=1 --partition=volta-x86 -C cpu_family:haswell" + +.a100: &a100 + SINGULARITY_CUDA_ARCH: 80 + SCHEDULER_PARAMETERS: "--nodes=1 --partition=shared-gpu-ampere" ####################### # Job Script Template # ####################### +.download_prereq: + stage: prepare + script: + - wget https://github.com/lanl/singularity-eos/releases/download/${SINGULARITY_GOLDFILES_VERSION}/goldfiles.tar.gz + artifacts: + paths: + - goldfiles.tar.gz + .test: stage: build_n_test - extends: - - .job + before_script: + - echo "Running on $(hostname)" + - section() { echo $'\e[0K'"section_$1:$(date +%s):$2"$'\r\e[0K'"${3+${COLOR_CYAN}$3${COLOR_PLAIN}}"; } + - export PYTHONNOUSERSITE=1 + - export SPACK_DISABLE_LOCAL_CONFIG=true + - export SPACK_SKIP_MODULES=true + - export TMP_USER_PROJECT_DIR="/tmp/${USER}/${CI_PROJECT_NAME}/${CI_JOB_NAME}" + - export PROJECT_TMP_CI_DIR=${PROJECT_TMP_CI_DIR:-${TMP_USER_PROJECT_DIR}} + - export SPACK_USER_CACHE_PATH="${PROJECT_TMP_CI_DIR}/spack-local" + - export DEVEL_SPACK_ROOT="${PROJECT_TMP_CI_DIR}/spack" + - export DEVEL_SPACK_MIRROR="${CI_PROJECT_DIR}/spack-mirror" + - rm -rf ${SPACK_USER_CACHE_PATH} ${DEVEL_SPACK_ROOT} + - | + if [[ -z "${PROJECT_TMP_SPACK_DIR}" ]]; then + export PROJECT_SPACK_ROOT="${XCAP_PROJECT_DIR}/spack-${TESTING_CLUSTER}" + else + export PROJECT_SPACK_ROOT="${XCAP_PROJECT_DIR}/${PROJECT_TMP_SPACK_DIR}-${TESTING_CLUSTER}" + fi + - section start "spack_init[collapsed=true]" "Creating Spack instance at ${DEVEL_SPACK_ROOT}" + - echo "Upstream ${PROJECT_SPACK_ROOT}" + - mkdir -m 2770 -p ${PROJECT_TMP_CI_DIR} + - | + rsync -rpl \ + --exclude=".git" \ + --exclude={"*__pycache__*","*.pyc"} \ + --include="etc/spack/**" \ + --include="lib/spack/**" \ + --exclude-from=${PROJECT_SPACK_ROOT}/.gitignore \ + ${PROJECT_SPACK_ROOT}/ ${DEVEL_SPACK_ROOT}/ + - sed -i "s;xcap-admin;xcap;g" "${DEVEL_SPACK_ROOT}/etc/spack/packages.yaml" + - source ${DEVEL_SPACK_ROOT}/share/spack/setup-env.sh + - spack --version + - spack compiler list + - section end spack_init script: - - module load gcc/${SINGULARITY_EOS_GCC_VERSION} - - module load cuda/${SINGULARITY_EOS_CUDA_VERSION} + - | + if [[ "${TESTING_CLUSTER}" = "rocinante" ]]; then + module load PrgEnv-gnu + module load gcc/${SINGULARITY_EOS_GCC_VERSION} + else + module load gcc/${SINGULARITY_EOS_GCC_VERSION} + module load cuda/${SINGULARITY_EOS_CUDA_VERSION} + module load openmpi/${SINGULARITY_EOS_OPENMPI_VERSION}-gcc_${SINGULARITY_EOS_GCC_VERSION} + fi - | if [[ "${CI_COMMIT_BRANCH}" == "${CI_DEFAULT_BRANCH}" ]]; then section start "spack_build[collapsed=true]" "Building via Spack" - mkdir -p spack_build_env spack env create spack_build_env spack env activate spack_build_env + spack repo add ${DEVEL_SPACK_ROOT}/var/spack/repos/xcap_deployment spack repo add spack-repo - spack config add upstreams:default:install_tree:${SINGULARITY_EOS_SPACK_DIR}/opt/spack/ + spack develop --no-clone -p ${CI_PROJECT_DIR}/utils/spiner spiner@main + spack develop --no-clone -p ${CI_PROJECT_DIR}/utils/ports-of-call ports-of-call@main + spack config add upstreams:default:install_tree:${PROJECT_SPACK_ROOT}/opt/spack/ spack dev-build -j $(nproc) ${SINGULARITY_EOS_SPACK_SPEC} spack env deactivate section end spack_build fi - section start "spack_env[collapsed=true]" "Creating Spack environment" - - mkdir -p spack_env - spack env create spack_env - spack env activate spack_env + - spack repo add ${DEVEL_SPACK_ROOT}/var/spack/repos/xcap_deployment - spack repo add spack-repo - - spack config add upstreams:default:install_tree:${SINGULARITY_EOS_SPACK_DIR}/opt/spack/ + - spack develop --no-clone -p ${CI_PROJECT_DIR}/utils/spiner spiner@main + - spack develop --no-clone -p ${CI_PROJECT_DIR}/utils/ports-of-call ports-of-call@main + - spack develop --no-clone -p ${CI_PROJECT_DIR} singularity-eos@main + - spack config add upstreams:default:install_tree:${PROJECT_SPACK_ROOT}/opt/spack/ - spack spec -I ${SINGULARITY_EOS_SPACK_SPEC} - spack add ${SINGULARITY_EOS_SPACK_SPEC} - spack install -j $(nproc) --show-log-on-error --no-checksum --yes-to-all -u cmake @@ -143,6 +196,7 @@ before_script: - | cmake -DCMAKE_INSTALL_PREFIX=${CI_PROJECT_DIR}/install ${SINGULARITY_CMAKE_CXX_COMPILER_FLAG} \ -DCMAKE_BUILD_TYPE=${SINGULARITY_EOS_BUILD_TYPE} \ + -DCMAKE_CXX_STANDARD=${SINGULARITY_EOS_CXX_STANDARD} \ -DSINGULARITY_USE_EOSPAC=ON \ -DSINGULARITY_USE_SPINER=ON \ -DSINGULARITY_USE_SPINER_WITH_HDF5=ON \ @@ -158,6 +212,7 @@ before_script: -DSINGULARITY_USE_KOKKOS=${SINGULARITY_USE_CUDA:-OFF} \ -DSINGULARITY_USE_KOKKOSKERNELS=${SINGULARITY_USE_CUDA:-OFF} \ -DSINGULARITY_USE_FORTRAN=${SINGULARITY_USE_FORTRAN:-OFF} \ + -DSINGULARITY_GOLDFILE_URL=file://${CI_PROJECT_DIR}/goldfiles.tar.gz \ .. - make -j $(nproc) || make VERBOSE=1 - | @@ -181,48 +236,99 @@ before_script: # Jobs # ######## +download_prereq: + extends: + - .download_prereq + test_gnu_skylake: - <<: *job_def + needs: [download_prereq] extends: .test variables: <<: *skylake <<: *python -test_gnu_power9: - <<: *job_def +test_x86_volta_gpu: + needs: [download_prereq] extends: .test variables: - <<: *power9 - <<: *python - -test_gnu_power9_gpu: - <<: *job_def - extends: .test - variables: - <<: *power9 + <<: *x86volta <<: *buildtype_release <<: *gpu -test_x86_volta_gpu: - <<: *job_def +test_x86_ampere_gpu: + needs: [download_prereq] extends: .test - variables: - <<: *x86volta + variables: + <<: *a100 <<: *buildtype_release <<: *gpu install_gnu_skylake_fort: - <<: *job_def + needs: [download_prereq] + extends: .test + variables: + <<: *skylake + <<: *python + <<: *fort + +install_gnu_skylake_fort_kokkos: + needs: [download_prereq] + extends: .test + variables: + <<: *skylake + <<: *python + <<: *fort + SINGULARITY_EOS_SPACK_SPEC: "singularity-eos@main+python+mpi+tests+kokkos+spiner+hdf5+kokkos-kernels%gcc@=${SINGULARITY_EOS_GCC_VERSION} ^kokkos std=${SINGULARITY_EOS_CXX_STANDARD} +openmp ^openmpi@${SINGULARITY_EOS_OPENMPI_VERSION}" + +install_gnu_skylake_fort_kokkos_cxx17: + needs: [download_prereq] extends: .test variables: <<: *skylake <<: *python <<: *fort + SINGULARITY_EOS_CXX_STANDARD: 17 + SINGULARITY_EOS_SPACK_SPEC: "singularity-eos@main+python+mpi+tests+kokkos+spiner+hdf5+kokkos-kernels%gcc@=${SINGULARITY_EOS_GCC_VERSION} ^kokkos std=${SINGULARITY_EOS_CXX_STANDARD} +openmp ^openmpi@${SINGULARITY_EOS_OPENMPI_VERSION}" + +install_gnu_skylake_fort_static_kokkos: + needs: [download_prereq] + extends: .test + variables: + <<: *skylake + <<: *python + <<: *fort + SINGULARITY_EOS_SPACK_SPEC: "singularity-eos@main+python+mpi+tests+kokkos+spiner+hdf5+kokkos-kernels%gcc@=${SINGULARITY_EOS_GCC_VERSION} ^kokkos std=${SINGULARITY_EOS_CXX_STANDARD} ~shared +openmp ^kokkos-kernels~shared ^openmpi@${SINGULARITY_EOS_OPENMPI_VERSION}" install_gnu_skylake_nofort: - <<: *job_def + needs: [download_prereq] extends: .test variables: <<: *skylake <<: *python <<: *nofort + +test_gnu_rocinante: + needs: [download_prereq] + extends: + - .rocinante_batch + - .test + variables: + <<: *python + +install_gnu_rocinante_fort: + needs: [download_prereq] + extends: + - .rocinante_batch + - .test + variables: + <<: *python + <<: *fort + +install_gnu_rocinante_nofort: + needs: [download_prereq] + extends: + - .rocinante_batch + - .test + variables: + <<: *python + <<: *nofort diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f91381416..cd69599b40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,36 @@ ## Current develop -### Fixed (Repair bugs, etc) - ### Added (new features/APIs/variables/...) +- [[PR377]](https://github.com/lanl/singularity-eos/pull/377) Moved much of the variant creating machinery and initialization machinery into separate header files. This is useful for downstream codes that use custom variants and helps with producing plugins. +- [[PR292]](https://github.com/lanl/singularity-eos/pull/292) Added Carnahan-Starling EoS +- [[PR#362]](https://github.com/lanl/singularity-eos/pull/362) Add lambda to thermalqs +- [[PR#339]](https://github.com/lanl/singularity-eos/pull/339) Added COMPONENTS to singularity-eos CMake install, allowing to select a minimal subset needed e.g. for Fortran bindings only +- [[PR#336]](https://github.com/lanl/singularity-eos/pull/336) Included code and documentation for a full, temperature consistent, Mie-Gruneisen EOS based on a pressure power law expansion in eta = 1-V/V0. PowerMG. +- [[PR334]](https://github.com/lanl/singularity-eos/pull/334) Include plugins infrastructure +- [[PR331]](https://github.com/lanl/singularity-eos/pull/331) Included code and documentation for a full, temperature consistent, Mie-Gruneisen EOS based on a linear Us-up relation. MGUsup. - [[PR326]](https://github.com/lanl/singularity-eos/pull/326) Document how to do a release +- [[PR#357]](https://github.com/lanl/singularity-eos/pull/357) Added support for C++17 (e.g., needed when using newer Kokkos). +- [[PR#382]](https://github.com/lanl/singularity-eos/pull/382) Added debug checks to the `get_sg_eos()` interface to ensure sane values are returned + +### Fixed (Repair bugs, etc) +- [[PR380]](https://github.com/lanl/singularity-eos/pull/380) Set material internal energy to 0 if not participating in the pte solve to make sure potentially uninitialized data is set. +- [[PR370]](https://github.com/lanl/singularity-eos/pull/370) Fix bulk modulus calculation in spiner EOS +- [[PR343]](https://github.com/lanl/singularity-eos/pull/343) Add chemical potentials to stellar collapse gold files +- [[PR342]](https://github.com/lanl/singularity-eos/pull/342) Fix missing using statement in stellar collapse root finding routines +- [[PR341]](https://github.com/lanl/singularity-eos/pull/341) Short-circuit HDF5 machinery when cray-wrappers used in-tree +- [[PR340]](https://github.com/lanl/singularity-eos/pull/335) Fix in-tree builds with plugin infrastructure +- [[PR335]](https://github.com/lanl/singularity-eos/pull/335) Fix missing hermite.hpp in CMake install required for Helmholtz EOS +- [[PR356]](https://github.com/lanl/singularity-eos/pull/356) Guard against FPEs in the PTE solver +- [[PR356]](https://github.com/lanl/singularity-eos/pull/356) Update CMake for proper Kokkos linking in Fortran interface +- [[PR373]](https://github.com/lanl/singularity-eos/pull/373) Initialize cache in `get_sg_eos*` functions +- [[PR374]](https://github.com/lanl/singularity-eos/pull/374) Make the Davis EOS more numerically robust +- [[PR383]](https://github.com/lanl/singularity-eos/pull/383) Fix bug in step scaling for PTE solver ### Changed (changing behavior/API/variables/...) +- [[PR363]](https://github.com/lanl/singularity-eos/pull/363) Template lambda values for scalar calls +- [[PR372]](https://github.com/lanl/singularity-eos/pull/372) Removed E0 from Davis Products EOS in favor of using the shifted EOS modifier. CHANGES API! +- [[PR#382]](https://github.com/lanl/singularity-eos/pull/382) Changed `get_sg_eos()` API to allow optionally specifying the mass fraction cutoff for materials to participate in the PTE solver ### Infrastructure (changes irrelevant to downstream codes) - [[PR329]](https://github.com/lanl/singularity-eos/pull/329) Move vinet tests into analytic test suite @@ -22,7 +46,7 @@ Date: 11/28/2023 - [[PR278]](https://github.com/lanl/singularity-eos/pull/278) Fixed EOSPAC unit conversion errors for scalar lookups - [[PR316]](https://github.com/lanl/singularity-eos/pull/316) removed `fmax-errors=3` from `singularity-eos` compile flags - [[PR296]](https://github.com/lanl/singularity-eos/pull/296) changed `CMAKE_SOURCE_DIR` to `PROJECT_SOURCE_DIR` to fix downstream submodule build -- [[PR291]](https://github.com/lanl/singularity-eos/pull/291) package.py updates to reflect new CMake options +- [[PR291]](https://github.com/lanl/singularity-eos/pull/291) package.py updates to reflect new CMake options - [[PR290]](https://github.com/lanl/singularity-eos/pull/290) Added target guards on export config - [[PR288]](https://github.com/lanl/singularity-eos/pull/288) Don't build tests that depend on spiner when spiner is disabled - [[PR287]](https://github.com/lanl/singularity-eos/pull/287) Fix testing logic with new HDF5 options @@ -40,6 +64,7 @@ Date: 11/28/2023 - [[PR308]](https://github.com/lanl/singularity-eos/pull/308) spack builds +fortran now compile via correct blocking out of interfaces via preprocessor ifdef ### Added (new features/APIs/variables/...) +- [[PR338]](https://github.com/lanl/singularity-eos/pull/338) added chemical potentials from EoS - [[PR269]](https://github.com/lanl/singularity-eos/pull/269) Add SAP Polynomial EoS - [[PR278]](https://github.com/lanl/singularity-eos/pull/278) Added EOSPAC option functionality in class constructor - [[PR278]](https://github.com/lanl/singularity-eos/pull/278) Added a new function for returning the minimum energy as a function of density for an EOS (only EOSPAC at the moment) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7353b4aea1..124b2d780e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ # ------------------------------------------------------------------------------# -# © 2021-2023. Triad National Security, LLC. All rights reserved. This program +# © 2021-2024. Triad National Security, LLC. All rights reserved. This program # was produced under U.S. Government contract 89233218CNA000001 for Los Alamos # National Laboratory (LANL), which is operated by Triad National Security, LLC # for the U.S. Department of Energy/National Nuclear Security Administration. @@ -29,9 +29,9 @@ project( list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") -set(SINGULARITY_GOLDFILES_VERSION "goldfiles-1.6.2") +set(SINGULARITY_GOLDFILES_VERSION "goldfiles-1.8.0") set(SINGULARITY_GOLDFILE_HASH - 33ef74b29937cc1347b525f72662933dd2b0556550f6541f97fc1de8a01c3c2a) + 249772f3314c4b6b9386aa08895280698ae905ef188f4383b819f28c1484603b) # ------------------------------------------------------------------------------# # Options @@ -118,6 +118,11 @@ option(SINGULARITY_FORCE_SUBMODULE_MODE "Submodule mode" OFF) option(SINGULARITY_PATCH_MPARK_VARIANT "Apply GPU patch to mpark-variant submodule" ON) +# Plugins +set(SINGULARITY_PLUGINS "" CACHE STRING "List of paths to plugin directories") +set(SINGULARITY_VARIANT "singularity-eos/eos/default_variant.hpp" CACHE STRING + "The include path for the file containing the definition of singularity::EOS.") + # ------------------------------------------------------------------------------# # singularity-eos Library # ------------------------------------------------------------------------------# @@ -130,12 +135,17 @@ include(singularity-eos/kokkos) include(singularity-eos/spiner) include(singularity-eos/ports-of-call) -add_library(singularity-eos) +add_library(singularity-eos INTERFACE) add_library(singularity-eos::singularity-eos ALIAS singularity-eos) -# ? -target_include_directories(singularity-eos - PUBLIC $) +# interface target to collect runtime libraries +add_library(singularity-eos_Common INTERFACE) +add_library(singularity-eos::singularity-eos_Common ALIAS singularity-eos_Common) + +add_library(singularity-eos_Interface INTERFACE) +add_library(singularity-eos::singularity-eos_Interface ALIAS singularity-eos_Interface) +target_link_libraries(singularity-eos_Interface INTERFACE singularity-eos_Common) +target_link_libraries(singularity-eos INTERFACE singularity-eos_Interface) # ------------------------------------------------------------------------------# # Compiler & language setup @@ -157,11 +167,17 @@ if(SINGULARITY_BUILD_PYTHON) set(CMAKE_POSITION_INDEPENDENT_CODE ON) endif() +# require at least C++14, but allow newer versions to become a client requirement if +# explicitly set at build time (needed for building with newer Kokkos) +if(CMAKE_CXX_STANDARD) + target_compile_features(singularity-eos_Interface INTERFACE cxx_std_${CMAKE_CXX_STANDARD}) +else() + target_compile_features(singularity-eos_Interface INTERFACE cxx_std_14) +endif() + # checks if this is our build, or we've been imported via `add_subdirectory` NB: # this should make the `option(SINGULARITY_SUBMODULE_MODE ...)` unnecessary if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) - set(CMAKE_CXX_STANDARD 14) - set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) else() message( @@ -222,8 +238,9 @@ if(SINGULARITY_SUBMODULE_MODE) CACHE BOOL "" FORCE) endif() -# side-projects TODO: hdf5 again if(SINGULARITY_BUILD_EXAMPLES) -# add_subdirectory(example) endif() +if(SINGULARITY_BUILD_EXAMPLES) + add_subdirectory(example) +endif() # add subdirs if(SINGULARITY_BUILD_PYTHON) @@ -236,21 +253,23 @@ endif() # defines if(SINGULARITY_USE_SINGLE_LOGS) - target_compile_definitions(singularity-eos PUBLIC SINGULARITY_USE_SINGLE_LOGS) + target_compile_definitions(singularity-eos_Interface INTERFACE SINGULARITY_USE_SINGLE_LOGS) endif() if(SINGULARITY_USE_HIGH_RISK_MATH) - target_compile_definitions(singularity-eos - PUBLIC SINGULARITY_USE_HIGH_RISK_MATH) + target_compile_definitions(singularity-eos_Interface + INTERFACE SINGULARITY_USE_HIGH_RISK_MATH) endif() - if(SINGULARITY_TEST_SESAME) - target_compile_definitions(singularity-eos PRIVATE SINGULARITY_TEST_SESAME) + target_compile_definitions(singularity-eos_Interface INTERFACE SINGULARITY_TEST_SESAME) endif() if(SINGULARITY_BUILD_CLOSURE) - target_compile_definitions(singularity-eos PRIVATE SINGULARITY_BUILD_CLOSURE) + target_compile_definitions(singularity-eos_Interface INTERFACE SINGULARITY_BUILD_CLOSURE) endif() if(SINGULARITY_USE_HELMHOLTZ) - target_compile_definitions(singularity-eos PUBLIC SINGULARITY_USE_HELMHOLTZ) + target_compile_definitions(singularity-eos_Interface INTERFACE SINGULARITY_USE_HELMHOLTZ) +endif() +if(SINGULARITY_USE_SPINER_WITH_HDF5) + target_compile_definitions(singularity-eos_Interface INTERFACE SINGULARITY_USE_SPINER_WITH_HDF5) endif() # ------------------------------------------------------------------------------# @@ -269,12 +288,12 @@ endif() # cases. if(SINGULARITY_USE_SPINER_WITH_HDF5) - singularity_enable_hdf5(singularity-eos) + singularity_enable_hdf5(singularity-eos_Common) endif() if(SINGULARITY_USE_EOSPAC) # NB This will add the `eospac-wrapper` directory. - singularity_enable_eospac(singularity-eos) + singularity_enable_eospac(singularity-eos_Common) endif() if(SINGULARITY_SUBMODULE_MODE) @@ -315,23 +334,25 @@ else() endif() -singularity_enable_mpark_variant(singularity-eos) -singularity_enable_ports_of_call(singularity-eos) +singularity_enable_mpark_variant(singularity-eos_Interface) +singularity_enable_ports_of_call(singularity-eos_Interface) if(SINGULARITY_USE_SPINER) - singularity_enable_spiner(singularity-eos) + singularity_enable_spiner(singularity-eos_Interface) # if(SINGULARITY_USE_SPINER_WITH_HDF5) - # singularity_enable_hdf5(singularity-eos) endif() + # singularity_enable_hdf5(singularity-eos_Interface) endif() endif() +# Both the interface (headers) and the library (compiled) need to link to Kokkos +# see get_sg_eos.cpp if(SINGULARITY_USE_KOKKOS) - singularity_enable_kokkos(singularity-eos) + singularity_enable_kokkos(singularity-eos_Common) if(SINGULARITY_USE_KOKKOSKERNELS) - singularity_enable_kokkoskernels(singularity-eos) + singularity_enable_kokkoskernels(singularity-eos_Common) endif() endif() if(SINGULARITY_USE_EIGEN) - singularity_enable_eigen(singularity-eos) + singularity_enable_eigen(singularity-eos_Interface) endif() # ----------------------------------------------------------------------------# @@ -359,58 +380,84 @@ if(SINGULARITY_BUILD_TESTS) endif() endif() -# ##########################OLD +# ------------------------------------------------------------------------------# +# Plugin infrastructure +# ------------------------------------------------------------------------------# +include(cmake/plugins.cmake) +set(PLUGIN_BUILD_ROOT "${CMAKE_CURRENT_BINARY_DIR}/plugins") + # ------------------------------------------------------------------------------# # singularity-eos library # ------------------------------------------------------------------------------# -# this subdirectory populates `EOS_HEADERS/EOS_SRCS` NOTE: these include path +# Here we populate `EOS_HEADERS/EOS_SRCS` NOTE: these include path # prefixes of subdirectories on files (e.g. eos/eos.hpp) see # singularity-eos/CMakeLists.txt - add_subdirectory(singularity-eos) -foreach(_header ${EOS_HEADERS}) - list(APPEND _install_headers ${_header}) - list(APPEND _headers singularity-eos/${_header}) +foreach(_plugin ${SINGULARITY_PLUGINS}) + message(STATUS "Adding plugin ${_plugin}...") + get_filename_component(BINDIR_LOC ${_plugin} NAME) + add_subdirectory(${_plugin} ${PLUGIN_BUILD_ROOT}/${BINDIR_LOC}) endforeach() -foreach(_src ${EOS_SRCS}) - list(APPEND _srcs singularity-eos/${_src}) -endforeach() +# TODO(JMM): Kind of nice to have? +get_property(eos_headers GLOBAL PROPERTY EOS_HEADERS) +target_sources(singularity-eos_Interface PRIVATE ${eos_headers}) +message(VERBOSE "EOS Headers:\n\t${eos_headers}") -target_sources(singularity-eos PRIVATE ${_srcs} ${_headers}) +if(SINGULARITY_BUILD_CLOSURE) + get_property(eos_srcs GLOBAL PROPERTY EOS_SRCS) + + if(eos_srcs) + add_library(singularity-eos_Library) + set_target_properties(singularity-eos_Library PROPERTIES OUTPUT_NAME singularity-eos) + add_library(singularity-eos::singularity-eos_Library ALIAS singularity-eos_Library) + # Public scope ensures explicit Kokkos dependency for library and anything + # that links to it + target_link_libraries(singularity-eos_Library PUBLIC singularity-eos_Common) + target_link_libraries(singularity-eos INTERFACE singularity-eos_Library) + target_sources(singularity-eos_Library PRIVATE ${eos_srcs}) + message(VERBOSE "EOS Library Sources:\n\t${eos_srcs}") + endif() +endif() -if(SINGULARITY_USE_FORTRAN) +if(TARGET singularity-eos_Library AND SINGULARITY_USE_FORTRAN) # Turn on preprocessor for fortran files - set_target_properties(singularity-eos PROPERTIES Fortran_PREPROCESS ON) + set_target_properties(singularity-eos_Library PROPERTIES Fortran_PREPROCESS ON) # make sure .mods are placed in build path, and installed along with includes - set_target_properties(singularity-eos PROPERTIES Fortran_MODULE_DIRECTORY + set_target_properties(singularity-eos_Library PROPERTIES Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/fortran) target_include_directories( - singularity-eos INTERFACE $ + singularity-eos_Library INTERFACE $ $) - set_target_properties(singularity-eos PROPERTIES Fortran_PREPROCESS ON) endif() # SINGULARITY_USE_FORTRAN -target_include_directories( - singularity-eos PUBLIC $ - $) +target_include_directories(singularity-eos_Interface INTERFACE + $ + $ + $ +) + +get_property(plugin_include_paths GLOBAL PROPERTY PLUGIN_INCLUDE_PATHS) +foreach(path ${plugin_include_paths}) + target_include_directories(singularity-eos_Interface INTERFACE $) +endforeach() # plug in collected includes/libs/definitions target_include_directories( - singularity-eos + singularity-eos_Interface PUBLIC ${SINGULARITY_PUBLIC_INCS} PRIVATE ${SINGULARITY_PRIVATE_INCS}) target_link_libraries( - singularity-eos + singularity-eos_Interface PUBLIC ${SINGULARITY_PUBLIC_LIBS} PRIVATE ${SINGULARITY_PRIVATE_LIBS}) target_compile_definitions( - singularity-eos + singularity-eos_Interface PUBLIC ${SINGULARITY_PUBLIC_DEFINES} PRIVATE ${SINGULARITY_PRIVATE_DEFINES}) @@ -429,9 +476,8 @@ set(with_better_flags "$") set(xlfix "$<${with_xlcxx}:-std=c++1y;-qxflag=disable__cplusplusOverride>") target_compile_options( - singularity-eos - PRIVATE ${xlfix} - PUBLIC $<${with_cuda}: + singularity-eos_Interface + INTERFACE $<${with_cuda}: $<${with_cxx}: --expt-relaxed-constexpr $<${with_warnings}: @@ -449,7 +495,26 @@ target_compile_options( > # cuda ) -target_link_options(singularity-eos PRIVATE ${xlfix}) +if(TARGET singularity-eos_Library) + target_compile_options(singularity-eos_Library PRIVATE ${xlfix}) + target_link_options(singularity-eos_Library PRIVATE ${xlfix}) + + # target_link_libraries(singularity-eos_Library PRIVATE singularity-eos_Interface) + # + # Can not use PRIVATE, since it would add singularity-eos_Interface as LINK_ONLY + # in the singularity-eos_Library export + # + # CMake 3.26 gives us $, for now we need to do this workaround + if(CMAKE_VERSION VERSION_LESS "3.26.0") + target_link_options(singularity-eos_Library PRIVATE $) + target_include_directories(singularity-eos_Library PRIVATE $) + target_compile_options(singularity-eos_Library PRIVATE $) + target_compile_definitions(singularity-eos_Library PRIVATE $) + target_sources(singularity-eos_Library PRIVATE $) + else() + target_link_libraries(singularity-eos_Library PRIVATE $) + endif() +endif() # ----------------------------------------------------------------------------# # Export/install diff --git a/README.md b/README.md index e0f81f01e0..d5beb1f262 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ Singularity EOS [![Tests](https://github.com/lanl/singularity-eos/actions/workflows/tests.yml/badge.svg)](https://github.com/lanl/singularity-eos/actions/workflows/tests.yml) +[![status](https://joss.theoj.org/papers/9d2ab99bcafa1421e2c9576899cd17bc/status.svg)](https://joss.theoj.org/papers/9d2ab99bcafa1421e2c9576899cd17bc) + A collection of closure models and tools useful for multiphysics codes. ## Documentation diff --git a/cmake/install.cmake b/cmake/install.cmake index 3067aa5ed1..1499264d99 100644 --- a/cmake/install.cmake +++ b/cmake/install.cmake @@ -55,27 +55,57 @@ install(FILES ${PROJECT_SOURCE_DIR}/cmake/FindEOSPAC.cmake # install export target # ----------------------------------------------------------------------------# install( - TARGETS singularity-eos - EXPORT singularity-eosTargets + TARGETS singularity-eos_Common + EXPORT singularity-eos_Common DESTINATION ${CMAKE_INSTALL_LIBDIR}) install( - EXPORT singularity-eosTargets - FILE singularity-eosTargets.cmake + EXPORT singularity-eos_Common + FILE singularity-eos_Common.cmake NAMESPACE "singularity-eos::" DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/singularity-eos) +install( + TARGETS singularity-eos_Interface + EXPORT singularity-eos_Interface + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +install( + EXPORT singularity-eos_Interface + FILE singularity-eos_Interface.cmake + NAMESPACE "singularity-eos::" + COMPONENT singularity-eos_Interface + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/singularity-eos) + +if(TARGET singularity-eos_Library) + install( + TARGETS singularity-eos_Library + EXPORT singularity-eos_Library + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + + install( + EXPORT singularity-eos_Library + FILE singularity-eos_Library.cmake + NAMESPACE "singularity-eos::" + COMPONENT singularity-eos_Library + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/singularity-eos) +endif() + # ----------------------------------------------------------------------------# # Install headers # ----------------------------------------------------------------------------# # install singularity-eos headers -foreach(file ${_install_headers}) - get_filename_component(DIR ${file} DIRECTORY) - install(FILES singularity-eos/${file} - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/singularity-eos/${DIR}) +get_property(install_headers GLOBAL PROPERTY EOS_INSTALL_HEADERS) +foreach(src dst IN ZIP_LISTS eos_headers install_headers) + get_filename_component(DIR ${dst} DIRECTORY) + install(FILES ${src} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${DIR}) endforeach() # file +# Special sauce so generated file has proper include path +install(FILES ${CMAKE_BINARY_DIR}/generated/singularity-eos/eos/eos.hpp + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/singularity-eos/eos) + # install the fortran modules NB: cmake doesn't provide a clean way to handle if(SINGULARITY_USE_FORTRAN) install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/fortran/ @@ -89,10 +119,22 @@ endif() # same as install step, but just places the file in the build tree. useful for # downstream projects that use the source directly export( - EXPORT singularity-eosTargets - FILE ${CMAKE_CURRENT_BINARY_DIR}/singularity-eosTargets.cmake + EXPORT singularity-eos_Common + FILE ${CMAKE_CURRENT_BINARY_DIR}/singularity-eos_Common.cmake NAMESPACE singularity-eos::) +export( + EXPORT singularity-eos_Interface + FILE ${CMAKE_CURRENT_BINARY_DIR}/singularity-eos_Interface.cmake + NAMESPACE singularity-eos::) + +if(TARGET singularity-eos_Library) + export( + EXPORT singularity-eos_Library + FILE ${CMAKE_CURRENT_BINARY_DIR}/singularity-eos_Library.cmake + NAMESPACE singularity-eos::) +endif() + # ----------------------------------------------------------------------------# # Data files # ----------------------------------------------------------------------------# diff --git a/cmake/plugins.cmake b/cmake/plugins.cmake new file mode 100644 index 0000000000..74d0c188e0 --- /dev/null +++ b/cmake/plugins.cmake @@ -0,0 +1,64 @@ +#------------------------------------------------------------------------------# +# © 2024. Triad National Security, LLC. All rights reserved. This +# program was produced under U.S. Government contract 89233218CNA000001 +# for Los Alamos National Laboratory (LANL), which is operated by Triad +# National Security, LLC for the U.S. Department of Energy/National +# Nuclear Security Administration. All rights in the program are +# reserved by Triad National Security, LLC, and the U.S. Department of +# Energy/National Nuclear Security Administration. The Government is +# granted for itself and others acting on its behalf a nonexclusive, +# paid-up, irrevocable worldwide license in this material to reproduce, +# prepare derivative works, distribute copies to the public, perform +# publicly and display publicly, and to permit others to do so. +#------------------------------------------------------------------------------# + +set_property(GLOBAL PROPERTY EOS_SRCS "") +set_property(GLOBAL PROPERTY EOS_HEADERS "") +set_property(GLOBAL PROPERTY EOS_INSTALL_HEADERS "") +set_property(GLOBAL PROPERTY PLUGIN_TESTS "") +set_property(GLOBAL PROPERTY PLUGIN_INCLUDE_PATHS "") + +function(register_headers) + set(keyword_args PLUGIN) + cmake_parse_arguments(ARG "" "${keyword_args}" "" ${ARGN}) + set(variadic_args ${ARG_UNPARSED_ARGUMENTS}) + + get_property(eos_headers GLOBAL PROPERTY EOS_HEADERS) + get_property(install_headers GLOBAL PROPERTY EOS_INSTALL_HEADERS) + + foreach(arg IN LISTS variadic_args) + file(RELATIVE_PATH relative_path ${PROJECT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) + if (ARG_PLUGIN) + list(APPEND eos_headers ${relative_path}/${ARG_PLUGIN}/${arg}) + list(APPEND install_headers ${ARG_PLUGIN}/${arg}) + else() + list(APPEND eos_headers ${relative_path}/${arg}) + list(APPEND install_headers ${relative_path}/${arg}) + endif() + endforeach() + set_property(GLOBAL PROPERTY EOS_HEADERS "${eos_headers}") + set_property(GLOBAL PROPERTY EOS_INSTALL_HEADERS "${install_headers}") +endfunction() + +function(register_srcs) + get_property(eos_srcs GLOBAL PROPERTY EOS_SRCS) + foreach(arg IN LISTS ARGN) + file(RELATIVE_PATH relative_path ${PROJECT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) + list(APPEND eos_srcs ${relative_path}/${arg}) + endforeach() + set_property(GLOBAL PROPERTY EOS_SRCS "${eos_srcs}") +endfunction() + +function(register_tests) + get_property(plugin_tests GLOBAL PROPERTY PLUGIN_TESTS) + foreach(arg IN LISTS ARGN) + list(APPEND plugin_tests ${CMAKE_CURRENT_SOURCE_DIR}/${arg}) + endforeach() + set_property(GLOBAL PROPERTY PLUGIN_TESTS "${plugin_tests}") +endfunction() + +macro(export_plugin) + get_property(plugin_include_paths GLOBAL PROPERTY PLUGIN_INCLUDE_PATHS) + list(APPEND plugin_include_paths ${CMAKE_CURRENT_SOURCE_DIR}) + set_property(GLOBAL PROPERTY PLUGIN_INCLUDE_PATHS "${plugin_include_paths}") +endmacro() diff --git a/cmake/singularity-eos/Eigen3.cmake b/cmake/singularity-eos/Eigen3.cmake index 04fbf99d38..c8dd72a855 100644 --- a/cmake/singularity-eos/Eigen3.cmake +++ b/cmake/singularity-eos/Eigen3.cmake @@ -19,5 +19,5 @@ macro(singularity_find_eigen) endmacro() macro(singularity_enable_eigen target) - target_link_libraries(${target} PUBLIC Eigen3::Eigen) + target_link_libraries(${target} INTERFACE Eigen3::Eigen) endmacro() diff --git a/cmake/singularity-eos/eospac.cmake b/cmake/singularity-eos/eospac.cmake index 42d1b160f8..ce7d6933de 100644 --- a/cmake/singularity-eos/eospac.cmake +++ b/cmake/singularity-eos/eospac.cmake @@ -2,11 +2,11 @@ macro(singularity_enable_eospac target) if(NOT TARGET EOSPAC::eospac) find_package(EOSPAC REQUIRED) endif() - target_link_libraries(${target} PUBLIC EOSPAC::eospac) - target_compile_definitions(${target} PUBLIC SINGULARITY_USE_EOSPAC) + target_link_libraries(${target} INTERFACE EOSPAC::eospac) + target_compile_definitions(${target} INTERFACE SINGULARITY_USE_EOSPAC) add_subdirectory(${PROJECT_SOURCE_DIR}/eospac-wrapper) - target_link_libraries(${target} PUBLIC eospac-wrapper) + target_link_libraries(${target} INTERFACE eospac-wrapper) endmacro() diff --git a/cmake/singularity-eos/hdf5.cmake b/cmake/singularity-eos/hdf5.cmake index 83f58e5fdb..7e05283447 100644 --- a/cmake/singularity-eos/hdf5.cmake +++ b/cmake/singularity-eos/hdf5.cmake @@ -37,53 +37,58 @@ macro(singularity_enable_hdf5 target) REQUIRED) endif() - # I'm bailing out here if these arn't filled in. I don't know if this is - # correct for every downstream use, but right now we need to enforce some kind - # of uniformity, otherwise we will need 100s of toolchain files JUST for hdf5 + # If we're doing an in-tree cray build, skip all this stuff. Fixes + # in-tree builds on Roci + Chicoma This is if (NOT (IN_TREE AND + # CRAY_THING)), but no composite expressions in cmake + if(NOT HDF5_C_COMPILER_EXECUTABLE_NO_INTERROGATE OR NOT SINGULARITY_FORCE_SUBMODULE_MODE) - if(NOT HDF5_LIBRARIES OR NOT HDF5_INCLUDE_DIRS) - message(SEND_ERROR "Could not locate the required HDF5 libraries!") - message(SEND_ERROR "-- HDF5_LIBRARIES=\"${HDF5_LIBRARIES}\"") - message(SEND_ERROR "-- HDF5_INCLUDE_DIRS=\"${HDF5_INCLUDE_DIRS}\"") - message(FATAL_ERROR "Cannot continue without HDF5 libraries!") - endif() - - # NOTE: `HDF5_LIBRARIES` should have "all requested bindings" according to - # docs, but some distributions completely seperate the HL libs to - # `HDF5_HL_LIBRARIES`. or sometimes they don't. So, check for HL, if it's not - # set, then check if they are placed in HDF5_LIBRARIES (simple substring - # search). If, finally, they're not found then bail. - if(NOT HDF5_HL_LIBRARIES) - string(FIND ${HDF5_LIBRARIES} "hdf5_hl" _hl_in_libs) - # if HL libs are not found in HDF5_LIBRARIES, then bail - if(_hl_in_libs LESS 0) - message( - SEND_ERROR - "Found HDF5 libraries, but could not locate required HDF5_HL libraries!" - ) + # I'm bailing out here if these arn't filled in. I don't know if this is + # correct for every downstream use, but right now we need to enforce some kind + # of uniformity, otherwise we will need 100s of toolchain files JUST for hdf5 + if(NOT HDF5_LIBRARIES OR NOT HDF5_INCLUDE_DIRS) + message(SEND_ERROR "Could not locate the required HDF5 libraries!") message(SEND_ERROR "-- HDF5_LIBRARIES=\"${HDF5_LIBRARIES}\"") - message(SEND_ERROR "-- HDF5_HL_LIBRARIES=\"${HDF5_HL_LIBRARIES}\"") - message(FATAL_ERROR "Cannot continue without HDF5 and HDF5_HL libraries!") + message(SEND_ERROR "-- HDF5_INCLUDE_DIRS=\"${HDF5_INCLUDE_DIRS}\"") + message(FATAL_ERROR "Cannot continue without HDF5 libraries!") endif() - endif() - - target_include_directories(${target} SYSTEM PUBLIC ${HDF5_INCLUDE_DIRS}) - target_link_libraries(${target} PUBLIC ${HDF5_LIBRARIES} ${HDF5_HL_LIBRARIES}) - - if(HDF5_IS_PARALLEL) - # find_package(MPI COMPONENTS C CXX REQUIRED) - # target_link_libraries(${target} PUBLIC MPI::MPI_C MPI::MPI_CXX) - enable_language(C) - find_package( - MPI - COMPONENTS C CXX - REQUIRED) - target_link_libraries(${target} PUBLIC MPI::MPI_CXX) - set(SINGULARITY_USE_SPINER_WITH_PARALLEL_HDF5 - ON - CACHE BOOL "" FORCE) - endif() + + # NOTE: `HDF5_LIBRARIES` should have "all requested bindings" according to + # docs, but some distributions completely seperate the HL libs to + # `HDF5_HL_LIBRARIES`. or sometimes they don't. So, check for HL, if it's not + # set, then check if they are placed in HDF5_LIBRARIES (simple substring + # search). If, finally, they're not found then bail. + if(NOT HDF5_HL_LIBRARIES) + string(FIND ${HDF5_LIBRARIES} "hdf5_hl" _hl_in_libs) + # if HL libs are not found in HDF5_LIBRARIES, then bail + if(_hl_in_libs LESS 0) + message( + SEND_ERROR + "Found HDF5 libraries, but could not locate required HDF5_HL libraries!" + ) + message(SEND_ERROR "-- HDF5_LIBRARIES=\"${HDF5_LIBRARIES}\"") + message(SEND_ERROR "-- HDF5_HL_LIBRARIES=\"${HDF5_HL_LIBRARIES}\"") + message(FATAL_ERROR "Cannot continue without HDF5 and HDF5_HL libraries!") + endif() + endif() + + target_include_directories(${target} SYSTEM INTERFACE ${HDF5_INCLUDE_DIRS}) + target_link_libraries(${target} INTERFACE ${HDF5_LIBRARIES} ${HDF5_HL_LIBRARIES}) + + if(HDF5_IS_PARALLEL) + # find_package(MPI COMPONENTS C CXX REQUIRED) + # target_link_libraries(${target} INTERFACE MPI::MPI_C MPI::MPI_CXX) + enable_language(C) + find_package( + MPI + COMPONENTS C CXX + REQUIRED) + target_link_libraries(${target} INTERFACE MPI::MPI_CXX) + set(SINGULARITY_USE_SPINER_WITH_PARALLEL_HDF5 + ON + CACHE BOOL "" FORCE) + endif() + endif() # in tree cray - target_compile_definitions(${target} PUBLIC SINGULARITY_USE_HDF5) + target_compile_definitions(${target} INTERFACE SINGULARITY_USE_HDF5) endmacro() diff --git a/cmake/singularity-eos/kokkos.cmake b/cmake/singularity-eos/kokkos.cmake index fb782a028e..6d56a8be32 100644 --- a/cmake/singularity-eos/kokkos.cmake +++ b/cmake/singularity-eos/kokkos.cmake @@ -23,9 +23,9 @@ endmacro() macro(singularity_enable_kokkos target) - target_link_libraries(${target} PUBLIC Kokkos::kokkos) + target_link_libraries(${target} INTERFACE Kokkos::kokkos) - target_compile_definitions(${target} PUBLIC PORTABILITY_STRATEGY_KOKKOS) + target_compile_definitions(${target} INTERFACE PORTABILITY_STRATEGY_KOKKOS) # #TODO: shouldn't be needed target_compile_definitions(${target} PUBLIC # SPINER_USE_KOKKOS) @@ -108,6 +108,6 @@ macro(singularity_find_kokkoskernels) endmacro() macro(singularity_enable_kokkoskernels target) - target_compile_definitions(${target} PUBLIC SINGULARITY_USE_KOKKOSKERNELS) - target_link_libraries(${target} PUBLIC Kokkos::kokkoskernels) + target_compile_definitions(${target} INTERFACE SINGULARITY_USE_KOKKOSKERNELS) + target_link_libraries(${target} INTERFACE Kokkos::kokkoskernels) endmacro() diff --git a/cmake/singularity-eos/mpark_variant.cmake b/cmake/singularity-eos/mpark_variant.cmake index ca67972a4b..3a5776d4ee 100644 --- a/cmake/singularity-eos/mpark_variant.cmake +++ b/cmake/singularity-eos/mpark_variant.cmake @@ -21,5 +21,5 @@ macro(singularity_find_mpark_variant) endmacro() macro(singularity_enable_mpark_variant target) - target_link_libraries(${target} PUBLIC mpark_variant) + target_link_libraries(${target} INTERFACE mpark_variant) endmacro() diff --git a/cmake/singularity-eos/ports-of-call.cmake b/cmake/singularity-eos/ports-of-call.cmake index c38d85aabb..6d1e1424e1 100644 --- a/cmake/singularity-eos/ports-of-call.cmake +++ b/cmake/singularity-eos/ports-of-call.cmake @@ -9,5 +9,5 @@ macro(singularity_find_ports_of_call) endmacro() macro(singularity_enable_ports_of_call target) - target_link_libraries(${target} PUBLIC ports-of-call::ports-of-call) + target_link_libraries(${target} INTERFACE ports-of-call::ports-of-call) endmacro() diff --git a/cmake/singularity-eos/spiner.cmake b/cmake/singularity-eos/spiner.cmake index 3d5de88237..c8c6568f61 100644 --- a/cmake/singularity-eos/spiner.cmake +++ b/cmake/singularity-eos/spiner.cmake @@ -35,9 +35,9 @@ macro(singularity_enable_spiner target) target_compile_definitions( ${target} - PUBLIC + INTERFACE $<$:SINGULARITY_USE_SPINER> $<$:SINGULARITY_USE_SPINER_WITH_HDF5> ) - target_link_libraries(${target} PUBLIC spiner::spiner) + target_link_libraries(${target} INTERFACE spiner::spiner) endmacro() diff --git a/config/singularity-eosConfig.cmake.in b/config/singularity-eosConfig.cmake.in index 7557387ab2..351c768f73 100644 --- a/config/singularity-eosConfig.cmake.in +++ b/config/singularity-eosConfig.cmake.in @@ -20,27 +20,51 @@ # ------------------------------------------------------------------------------# # add singularity-eos cmake files # ------------------------------------------------------------------------------# -get_filename_component(singularity-eos_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" - PATH) if(NOT SINGULARITY_EOS_CMAKE) - get_filename_component(singularity-eos_CMAKE_BASE_DIR - "${singularity-eos_CMAKE_DIR}" DIRECTORY) message( STATUS "Found singularity-eos CMake Modules (appending CMAKE_MODULE_PATH): " - ${singularity-eos_CMAKE_BASE_DIR}) - list(APPEND CMAKE_MODULE_PATH ${singularity-eos_CMAKE_BASE_DIR}) + ${CMAKE_CURRENT_LIST_DIR}) + list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) set(SINGULARITY_EOS_CMAKE TRUE) endif() +# ------------------------------------------------------------------------------# +# check for selected components +# ------------------------------------------------------------------------------# +if(${CMAKE_FIND_PACKAGE_NAME}_FIND_COMPONENTS) + set(${CMAKE_FIND_PACKAGE_NAME}_known_components Interface Library) + foreach(comp IN LISTS ${CMAKE_FIND_PACKAGE_NAME}_FIND_COMPONENTS) + if(NOT comp IN_LIST ${CMAKE_FIND_PACKAGE_NAME}_known_components) + set(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE "singularity-eos unknown component: ${comp}") + set(${CMAKE_FIND_PACKAGE_NAME}_FOUND FALSE) + return() + endif() + endforeach() + set(${CMAKE_FIND_PACKAGE_NAME}_comps ${${CMAKE_FIND_PACKAGE_NAME}_FIND_COMPONENTS}) +else() + set(${CMAKE_FIND_PACKAGE_NAME}_comps Interface Library) +endif() + +foreach(comp IN LISTS ${CMAKE_FIND_PACKAGE_NAME}_comps) + if(${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED_${comp} AND NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/singularity-eos_${comp}.cmake) + set(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE "singularity-eos missing required component: ${comp}") + set(${CMAKE_FIND_PACKAGE_NAME}_FOUND FALSE) + return() + endif() +endforeach() + + # ------------------------------------------------------------------------------# # library dependencies # ------------------------------------------------------------------------------# include(CMakeFindDependencyMacro) -find_dependency(ports-of-call) - -find_dependency(mpark_variant) +# header-only dependencies +if("Interface" IN_LIST ${CMAKE_FIND_PACKAGE_NAME}_comps) + find_dependency(ports-of-call) + find_dependency(mpark_variant) +endif() if(@SINGULARITY_USE_SPINER@) find_dependency(spiner) @@ -75,9 +99,24 @@ if(@SINGULARITY_USE_EOSPAC@) endif() endif() +include(${CMAKE_CURRENT_LIST_DIR}/singularity-eos_Common.cmake) + +foreach(comp IN LISTS ${CMAKE_FIND_PACKAGE_NAME}_comps) + include(${CMAKE_CURRENT_LIST_DIR}/singularity-eos_${comp}.cmake OPTIONAL) +endforeach() + # ------------------------------------------------------------------------------# -# singularity-eos imported targets +# singularity-eos convenience target # ------------------------------------------------------------------------------# if(NOT TARGET singularity-eos AND NOT singularity-eos_BINARY_DIR) - include(${singularity-eos_CMAKE_DIR}/singularity-eosTargets.cmake) + add_library(singularity-eos INTERFACE) + add_library(singularity-eos::singularity-eos ALIAS singularity-eos) + + if("Interface" IN_LIST ${CMAKE_FIND_PACKAGE_NAME}_comps) + target_link_libraries(singularity-eos INTERFACE singularity-eos::singularity-eos_Interface) + endif() + + if("Library" IN_LIST ${CMAKE_FIND_PACKAGE_NAME}_comps) + target_link_libraries(singularity-eos INTERFACE singularity-eos::singularity-eos_Library) + endif() endif() diff --git a/doc/sphinx/ApproxForTH.pdf b/doc/sphinx/ApproxForTH.pdf new file mode 100644 index 0000000000..787bb114b8 Binary files /dev/null and b/doc/sphinx/ApproxForTH.pdf differ diff --git a/doc/sphinx/PMGvsMGUsupPress.pdf b/doc/sphinx/PMGvsMGUsupPress.pdf new file mode 100644 index 0000000000..f48a07debe Binary files /dev/null and b/doc/sphinx/PMGvsMGUsupPress.pdf differ diff --git a/doc/sphinx/SteinbergGammarho.pdf b/doc/sphinx/SteinbergGammarho.pdf new file mode 100644 index 0000000000..2b2aeeeb73 Binary files /dev/null and b/doc/sphinx/SteinbergGammarho.pdf differ diff --git a/doc/sphinx/index.rst b/doc/sphinx/index.rst index 8c114f6eef..ea170e3546 100644 --- a/doc/sphinx/index.rst +++ b/doc/sphinx/index.rst @@ -15,11 +15,14 @@ Documentation approved for unlimited release. LA-UR-21-31131. :caption: Contents: src/getting-started + src/examples src/philosophy src/building + src/integration src/using-eos src/models src/modifiers + src/customization src/using-closures src/python src/contributing diff --git a/doc/sphinx/src/building.rst b/doc/sphinx/src/building.rst index c320fed464..a25a60087a 100644 --- a/doc/sphinx/src/building.rst +++ b/doc/sphinx/src/building.rst @@ -41,17 +41,17 @@ provided below. A CMake configuration option is provided that allows developers to select a specific mode (``SINGULARITY_FORCE_SUBMODULE_MODE``), however this is intended for internal development only. The intended workflow is -to let ``singularity-eos`` decide that appropriate mode, which it +to let ``singularity-eos`` decide the appropriate mode, which it decides based on inspecting the project directory that the source resides in. Dependencies ------------ -``singularity-eos`` has a number of required and optional depdencies. +``singularity-eos`` has a number of required and optional depdencies. ====================================== =============================== =========================================== - Package Name Distribution Comment + Package Name Distribution Comment ====================================== =============================== =========================================== `ports-of-call`_ submodule / external Required `mpark_variant`_ submodule / external Required @@ -61,10 +61,10 @@ Dependencies `kokkos`_ submodule / external Optional; enables GPU offloading. `Eigen`_ submodule / external Optional; used for linear algebra on the CPU when doing mixed-cell closures. `kokkos-kernels`_ submodule / external Optional; used for linear algebra on the GPU when doing mixed-cell closures. - `pybind11`_ external / fetchable [*]_ Optional + `pybind11`_ external / fetchable [*]_ Optional ====================================== =============================== =========================================== -.. [*] availible as a git submodule for in-tree builds +.. [*] available as a git submodule for in-tree builds .. [*] located outside the build tree and discoverable by CMake .. [*] CMake can download and configure this source in-tree @@ -99,7 +99,7 @@ sections detailing those build modes. The main CMake options to configure building are in the following table: ====================================== ======= =========================================== - Option Default Comment + Option Default Comment ====================================== ======= =========================================== ``SINGULARITY_USE_SPINER`` ON Enables EOS objects that use ``spiner``. ``SINGULARITY_USE_FORTRAN`` ON Enable Fortran API for equation of state. @@ -108,6 +108,7 @@ The main CMake options to configure building are in the following table: ``SINGULARITY_BUILD_CLOSURE`` OFF Build the mixed cell closure models ``SINGULARITY_BUILD_TESTS`` OFF Build test infrastructure. ``SINGULARITY_BUILD_PYTHON`` OFF Build Python bindings. + ``SINGULARITY_BUILD_EXAMPLES`` OFF Build examples of ``singularity-eos`` in use. ``SINGULARITY_INVERT_AT_SETUP`` OFF For tests, pre-invert eospac tables. ``SINGULARITY_BETTER_DEBUG_FLAGS`` ON Enables nicer GPU debug flags. May interfere with in-tree builds as a submodule. ``SINGULARITY_HIDE_MORE_WARNINGS`` OFF Makes warnings less verbose. May interfere with in-tree builds as a submodule. @@ -143,7 +144,7 @@ These options are listed in the following table, along with their preconditions: ============================================== ================================================================================= =========================================== - Option Precondition Comment + Option Precondition Comment ============================================== ================================================================================= =========================================== ``SINGULARITY_USE_SPINER_WITH_HDF5`` ``SINGULARITY_USE_SPINER=ON`` Requests that ``spiner`` be configured for ``HDF5`` support. ``SINGULARITY_USE_CUDA`` ``SINGULARITY_USE_KOKKOS=ON`` Target nvidia GPUs for ``Kokkos`` offloading. @@ -180,7 +181,7 @@ presets, see the `cmake documentation on presets `__ .. warning:: - CMake presets are only available if ``singularity-eos`` is the + CMake presets are only available if ``singularity-eos`` is the top-level project. Predefined presets @@ -286,8 +287,8 @@ source should be placed below the top-level of a host project # An example directory layout when using singularity-eos in submodule mode my_project |_CMakeLists.txt - |_README.md - |_src + |_README.md + |_src |_include |_tpl/singularity-eos @@ -312,7 +313,7 @@ code, along with the interfaces of the internal dependencies .. code:: c++ - // in source of my_project + // in source of my_project #include // from the internal ports-of-call submodule @@ -348,7 +349,7 @@ expected to be discoverable by CMake. This can be done several ways invocation to be aware of these installs *standalone* mode is the mode used to install ``singularity-eos`` to a -system as a common library. If, for example, you use Spack to to install +system as a common library. If, for example, you use Spack to install packages, ``singularity-eos`` will be built and installed in *standalone* mode. @@ -368,7 +369,7 @@ overview of how to use Spack to develop and deploy ``singularigy-eos``, but for more in-depth information, please refer to the `official Spack documentation `__. -Preperation +Preparation ^^^^^^^^^^^ First, we need to clone the Spack repository. You can place this @@ -386,7 +387,7 @@ To start using Spack, we use the provided activation script .. code:: bash - # equivalent scripts for tcsh, fish are located here as well + # equivalent scripts for tcsh, fish are located here as well $> source ~/spack/share/spack/setup-env.sh You will always need to *activate* spack for each new shell. You may @@ -494,7 +495,7 @@ You may also manually edit the ``packages.yaml`` file to switch the ``buildable`` flag for the troublesome package, but you will need to be a least familiar with YAML schema. -First install with spack +First install with Spack ^^^^^^^^^^^^^^^^^^^^^^^^ Let's walk through a simple Spack workflow for installing. First, we @@ -522,7 +523,7 @@ library for multigrid methods. develop [git] https://github.com/hypre-space/hypre.git on branch master 2.28.0 https://github.com/hypre-space/hypre/archive/v2.28.0.tar.gz - # ... more versions listed + # ... more versions listed Variants: Name [Default] When Allowed values Description @@ -532,7 +533,7 @@ library for multigrid methods. gfx1030, gfx90c, gfx90a, gfx1101, gfx908, gfx1010, - # ... lots of amd targets listed + # ... lots of amd targets listed build_system [autotools] -- autotools Build systems supported by the package caliper [off] -- on, off Enable Caliper support complex [off] -- on, off Use complex values @@ -663,13 +664,13 @@ Installing ``singularity-eos`` using Spack ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ . warning:: - The spack build is currently experimental. + The spack build is currently experimental. Please report problems you havee as github issues. The spackage is available in the main `Spack`_ repositories, and we provide a spackage for ``singularity-eos`` witin the -the singularity-eos source repository. The distributed spackage may be -more up-to-date than the one in the main `Spack`_ repository. If you +the singularity-eos source repository. The distributed spackage may be +more up-to-date than the one in the main `Spack`_ repository. If you have spack installed, simply call .. _Spack: https://spack.io/ @@ -724,13 +725,13 @@ supports a number of relevant variants: | tests [off] | on, off | Build tests | +-----------------------------+-----------------+-----------------------------+ -Developing ``singularigy-eos`` using Spack +Developing ``singularity-eos`` using Spack ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Spack is a powerful tool that can help develop ``singularigy-eos`` for a +Spack is a powerful tool that can help develop ``singularity-eos`` for a variety of platforms and hardware. -1. Install the dependencies ``singularigy-eos`` needs using Spack +1. Install the dependencies ``singularity-eos`` needs using Spack .. code:: bash diff --git a/doc/sphinx/src/contributing.rst b/doc/sphinx/src/contributing.rst index 97e637e6d0..1344cffe37 100644 --- a/doc/sphinx/src/contributing.rst +++ b/doc/sphinx/src/contributing.rst @@ -6,7 +6,7 @@ Contributing ============= If you have any trouble with the project, or are interested in -participating, please contact us by creating an issue on the github +participating, please contact us by creating an issue on the GitHub repository, or submit a pull request! Pull request protocol @@ -37,7 +37,7 @@ useful output. For example: Several sets of tests are triggered on a pull request: a static format check, a docs buld, and unit tests of analytic models and the stellar -collapse model. These are run through github's CPU infrastructure. We +collapse model. These are run through GitHub's CPU infrastructure. We have a second set of tests run on a wider set of architectures that also access the Sesame library, which we are not able to make public. @@ -127,7 +127,7 @@ Interwoven Dependencies ``singularity-eos`` depends on several other open-source, Los Alamos maintained, projects. In particular, ``spiner`` and ``ports-of-call``. If you have issues with these projects, ideally -submit issues on the relevant github pages. However, if you can't +submit issues on the relevant GitHub pages. However, if you can't figure out where an issue belongs, no big deal. Submit where you can and we'll engage with you to figure out how to proceed. @@ -217,7 +217,7 @@ wrapped with ``#ifdef SINGULARITY_USE_EOSPAC``. This might look something like #endif >{}; -Note the placement of commas and angle brackets. This example excludes +Note the placement of commas and angle brackets. This example excludes Step 3: Create tests for your EOS ````````````````````````````````` @@ -229,7 +229,7 @@ same. In general, we recommend you copy the general structure of one of the existing EOS-specific unit tests. After creating your tests, you will need to include the ``.cpp`` for your new -test in the ``CMakeLists.txt`` file, +test in the ``CMakeLists.txt`` file, .. code-block:: cmake @@ -402,7 +402,7 @@ Some notes on style and code architecture but many of the coding habits advocated for by Holzmann produce long-lived, easy to understand, easy to parse, and easy to maintain code. And we take many of the rules to heart. Here are a few that are most - relevant to ``singularity-eos``. They have been adapted slightly to + relevant to ``singularity-eos``. They have been adapted slightly to our context. #. Avoid complex flow constructs such as gotos. @@ -458,7 +458,7 @@ style. Here we briefly discuss a few things one should be aware of. ``PORTABLE_FORCEINLINE_FUNCTION``. These macros are imported from the `ports-of-call`_ library and resolve to the appropriate decorations for a given device-side backend such as cuda so the code - compiles correctly. Code that doesn't need to run on device, + compiles correctly. Code that doesn't need to run on device, such as EOS class constructors, does not need these decorations. * **Relocatable device code:** It is common in C++ to split code @@ -714,7 +714,7 @@ Main``. Typically the branch for this merge request should be called full test suite passes for this PR. After that pull request is merged, go to the ``releases`` tab on the -right sidebar on github, and draft a new release. Set the tag to +right sidebar on GitHub, and draft a new release. Set the tag to ``v[release number]``, fill the comment with the changes in the changelog since the last release, and make the release. diff --git a/doc/sphinx/src/customization.rst b/doc/sphinx/src/customization.rst new file mode 100644 index 0000000000..53342dd2f8 --- /dev/null +++ b/doc/sphinx/src/customization.rst @@ -0,0 +1,143 @@ +.. _customization: + +Customizing ``singularity-eos`` +================================ + +Custom Variant +--------------- + +If you would like to create your own custom variant with additional +models (or a subset of models), you may do so by using the +``eos_variant`` class. For example, + +.. code-block:: cpp + + #include + using namespace singularity; + + using MyEOS_t = eos_variant; + +This will create a new type, ``MyEOS_t`` which contains only the +``IdealGas`` and ``Gruneisen`` classes. (All of these live under the +``singularity`` namespace.) + +Plugins +-------- + +.. warning:: + + Plugins are currently an experimental feature. Use at your own risk. + +``singularity-eos`` is also extensible via a plugins +infrastructure. Via plugins, you may define additional equations of +state and have them automatically built, tested, and installed by the +library. You may even include them in the default ``singularity-eos`` +variant type. + +.. note:: + + We note that a downstream code built on ``singularity-eos`` may + have no need of a plugin infrastructure, as you can write your own + EOS models and and choose your own ``Variant`` type for your code + all within your context. Plugins are a way of adding arbitrary code + to ``singularity-eos`` that you may wish to share accross multiple + downstream codes (for example). + +The easiest way to explain how to add a plugin is probably by +example. In the ``example`` directory of the ``singularity-eos`` +source tree is a ``plugin`` subdirectory containing an example +plugin. The example plugin contains an implementation of astrophysical +dust. In this context dust is a pressure-less gas. We implement this +with an equation of state that always returns zero pressure, but has a +temperature and specific heat. + +The plugin directory contains a ``CMakeLists.txt`` file (described +more below) and a subdirectory named ``dust``, which contains the +source code. The name of the subdirectory will specify how it may be +included in code referencing the plugin. For example, to include the +dust equation of state explicitly, a user of this plugin would use the +include statement + +.. code-block:: cpp + + #include + +You may have as many subdirectories as you like, one for each "include +path" you want to make available. + +The plugin directory also contains a ``tst`` directory, which contains +an implementation file ``tst/test_dust.cpp``, which contains several +Catch2 tests. See the contribution guide for a longer discussion of +the ``singularity-eos`` testing infrastructure. + +The ``CMakeLists.txt`` file registers the plugin with the build system +via several custom ``cmake`` functions provided by +``singularity-eos``. To register a header file (and most files in +``singularity-eos`` should be header files) we use (for example) + +.. code-block:: + + register_headers(PLUGIN dust dust.hpp dust_variant.hpp) + +This specifies that the ``dust`` subdirectory contains two header +files that the infrastructure should know about: ``dust.hpp`` and +``dust_variant.hpp``. One such line is required for every additional +top-level subdirectory of the plugin directory. + +The dust plugin has no source files, however, these may be registered with + +.. code-block:: + + register_srcs(src1 src2 src3 ...) + +note that ``register_srcs`` does **not** take the ``PLUGIN path`` +syntax. Simply use the relative path from the ``CMakeLists.txt`` file to the source +file. + +To register the test, we call + +.. code-block:: + + register_tests(tst/test_dust.cpp) + +As with source files, do not use the ``PLUGIN PATH`` syntax. Just use +the relative path to the ``cpp`` file containing the tests. + +Finally, call + +.. code-block:: + + export_plugin() + +to ensure the registrations described above are pushed to "top level" +scope of the build system. + +To use a plugin so-defined, you must tell the build system that it +exists at configure time. To do so, call + +.. code-block:: + + -DSINGULARITY_PLUGINS="/path/to/my/plugin1;/path/to/my/plugin2" + +where the above defines a semicolon-separated list of paths to plugin +directories. For example, to register the dust plugin: + +.. code-block:: + + -DSINGULARITY_PLUGINS=/path/to/singularity-eos/example/plugin + +Re-defining the default variant +-------------------------------- + +The ``dust`` plugin also contains a file ``dust/dust_variant.hpp``, +which contains a definition of the ``EOS`` type (i.e., a variant) but +with the dust equation of state included. To tell the infrastructure +to use **this** variant rather than the default, specify the "include +path" at configure time. For example: + +.. code-block:: + + -DSINGULARITY_VARIANT="dust/dust_variant.hpp" + +There may only be *one* definition for the ``SINGULARITY_VARIANT`` at +a time, so only specify for one of your plugins, if you have multiple. diff --git a/doc/sphinx/src/examples.rst b/doc/sphinx/src/examples.rst new file mode 100644 index 0000000000..51360cf832 --- /dev/null +++ b/doc/sphinx/src/examples.rst @@ -0,0 +1,65 @@ +.. _examples: + +Examples +========= + +The ``example`` directory of ``singularity-eos`` contains several +examples of using the code. You can build the examples by setting +``-DSINGULARITY_BUILD_EXAMPLES=ON`` at ``CMake`` configuration +time. For example: + +.. code-block:: bash + + # from singularity-eos repo + mkdir -p build && cd build + cmake .. -DSINGULARITY_BUILD_EXAMPLES=ON .. + make -j + +The available examples are listed below. + +Get Sound Speed and Pressure +------------------------------ + +The ``examples/get_sound_speed_press.cpp`` file implements a call go +``singularity-eos`` that computes pressure and sound speed from +density and energy for an ideal gas equation of state. It demonstrates +how to make this call both through individual calls to pressure and +bulk modulus, as well as by calling the in-one ``FillEos`` API. The +former looks something like this: + +.. code-block:: cpp + + // Loop through the cells and use the two function calls + for (int i = 0; i < Ncells; ++i) { + double sie = robust::ratio(uu[i], rho[i]); // convert to specific internal energy + P[i] = eos.PressureFromDensityInternalEnergy(rho[i], sie, lambda.data()); + double bmod = eos.BulkModulusFromDensityInternalEnergy(rho[i], sie, lambda.data()); + cs[i] = std::sqrt(robust::ratio(bmod, rho[i])); + } + +The exact same code is implemented via the python bindings in ``get_sound_speed_press.py``. + +Get SESAME State +------------------- + +If you build with both ``SpinerEOS`` and ``EOSPAC`` backends for +tabulated data, you can compare tabulated interpolations by calling +the ``get_sesame_state`` executable built via the +``get_sesame_state.cpp`` example file. You can call it as + +.. code-block:: bash + + get_sesame_state matid sp5_file_name rho T sie + +for some ``SESAME`` material index ``matid`` and some tabulated spiner +file ``sp5_file_name``, and a density, temperature and specific +internal energy to evaluate at. + +The example demonstrates how to call the pressure, energy, and +thermodynamic derivatives of a table at that point in phase space. + +Plugins +---------- + +The example directory also contains an example plugin that can be +included via the plugin infrastructure, as described in :ref:`our customization section `. diff --git a/doc/sphinx/src/getting-started.rst b/doc/sphinx/src/getting-started.rst index 7088af808e..6da789e70c 100644 --- a/doc/sphinx/src/getting-started.rst +++ b/doc/sphinx/src/getting-started.rst @@ -11,16 +11,16 @@ At it's most basic, you can download and compile ``singularity-eos`` with: cd singularity-eos mkdir bin cd bin - cmake -DSINGULARITY_FORCE_SUBMODULEMODE=ON -DSINGULARITY_USE_FORTRAN=OFF .. - make -j + cmake -DSINGULARITY_FORCE_SUBMODULE_MODE=ON -DSINGULARITY_USE_FORTRAN=OFF .. + make -j make install # optional: install into directory defined via CMAKE_INSTALL_PREFIX -This will downloady singularity-eos with no optional dependencies and +This will download ``singularity-eos`` with no optional dependencies and compile the capabilities available in that form. For more details, see :ref:`our build page `. If the library is in your include and lib paths (or you built it -in-tree), you can include the eos part of the library with +in-tree), you can include the ``eos`` part of the library with .. code-block:: cpp @@ -78,7 +78,7 @@ And that's it! Going Deeper -------------- -* You can find code examples in the ``examples`` source directory. +* You can find code examples in the ``example`` source directory. We describe them :ref:`here `. * To learn more about the design philosophy, look :ref:`here `. * To learn about how to build, look at :ref:`our build document `. * To learn more about the equation of state API, look :ref:`here `. diff --git a/doc/sphinx/src/integration.rst b/doc/sphinx/src/integration.rst new file mode 100644 index 0000000000..495b85a07d --- /dev/null +++ b/doc/sphinx/src/integration.rst @@ -0,0 +1,47 @@ +Integrating `singularity-eos` into a CMake project +================================================== + +Installing singularity-eos into a prefix, either manually or via Spack gives +you an installation that can be used in other projects via CMake. Assuming +your installation is visible to CMake, either by installing in a known prefix +or setting ``CMAKE_PREFIX_PATH`` manually, a CMake project can integrate +Singularity-EOS via ``find_package(singularity-eos)`` and using the provided +targets to link to it. + +.. code:: cmake + + find_package(singularity-eos) + ... + target_link_libraries(yourTarget PRIVATE singularity-eos::singularity-eos) + +The ``singularity-eos`` config module provides the following targets: + +``singularity-eos::singularity-eos_Interface``: + The C++ header-only library, adding the necessary include directories and + other dependencies such as mpark-variant and ports-of-call. + +``singularity-eos::singularity-eos_Library``: + The static or shared library installed when building with + ``SINGULARITY_BUILD_CLOSURE=on``. If ``SINGULARITY_USE_FORTRAN=on``, this also includes the + Fortran bindings and adds include path for its Fortran module. + +``singularity-eos::singularity-eos`` + Convenience target that contains either + ``singularity-eos::singularity-eos_Interface``, + ``singularity-eos::singularity-eos_Library``, or both, depending on the + COMPONENTS selection during ``find_package``. By default, if no COMPONENTS + are specified both are included. + +Example: Integrating singularity-eos into a Fortran code +-------------------------------------------------------- + +Fortran projects do not require the C++ header-only library and its +dependencies, but only the compiled Fortran bindings provided by +Singularity-EOS. To avoid unnecessary dependency checks by CMake, a Fortran +project would integrate Singularity-EOS as follows: + +.. code:: cmake + + find_package(singularity-eos COMPONENTS Library) + ... + target_link_libraries(yourTarget PRIVATE singularity-eos::singularity-eos) diff --git a/doc/sphinx/src/models.rst b/doc/sphinx/src/models.rst index 26846724af..205aa421c6 100644 --- a/doc/sphinx/src/models.rst +++ b/doc/sphinx/src/models.rst @@ -19,6 +19,8 @@ .. _StiffGas: https://doi.org/10.1016/j.ijthermalsci.2003.09.002 +.. _PowerMG: https://www.osti.gov/biblio/1762624 + EOS Models =========== @@ -542,6 +544,92 @@ these values are not set, they will be the same as those returned by the conditions are given, the return values of the :code:`ValuesAtReferenceState()` function will not be the same. +Carnahan-Starling +````````````````` + +The (quasi-exact) Carnahan-Starling model in ``singularity-eos`` takes +the form + +.. math:: + + P = Z(\rho) \rho (e-q) (\gamma-1) + +.. math:: + + Z(\rho) = \frac{1+\eta+\eta^2-\eta^3}{(1-\eta)^3}, + +where :math:`\eta` is the packing fraction given by + +.. math:: + + \eta = b\rho. + +The energy is related to the temperature through + +.. math:: + + e = C_V T + q, + +where :math:`q` is an energy offset. + +As with the Noble-Abel EOS, it should be noted that covolume is physically +significant as it represents the maximum compressibility of the gas, +and as a result it should be non-negative. + +The Carnahan-Starling EOS is intended to represent a hard sphere fluid, and the +covolume parameter, :math:`b`, can be related to the hard sphere +diameter, :math:`\sigma`, through + +.. math:: + + b = \frac{\pi}{6}\frac{\sigma^3}{M}, + +where :math:`M` is the molar mass of the gas. + +The entropy for the Carnahan-Starling EOS is given by + +.. math:: + + S = C_V \ln\left(\frac{T}{T_0}\right) + C_V (\gamma-1) \left\{ \ln\left(\frac{v} + {v_0}\right) - S^{CS} \right\} + q', + +.. math:: + S^{CS} = b\left(4\left(\frac{1}{v-b} - \frac{1}{v_0-b}\right)+ + b\left(\frac{1}{(v-b)^2} - \frac{1}{(v_0-b)^2}\right)\right) + +where :math:`S(\rho_0,T_0)=q'`. By default, :math:`T_0 = 298` K and the +reference density is given by + +.. math:: + + P_0 = \rho_0 Z(\rho_0) C_V T_0(\gamma-1), + +where :math:`P_0` is by default 1 bar. Denisty is obtained through root finding methods. + +The settable parameters for this EOS are :math:`\gamma-1`, specific +heat capacity (:math:`C_V`), covolume (:math:`b`) and offset internal energy (:math:`q`). Optionally, the reference state for the entropy calculation can +be provided by setting the reference temperature, pressure, and entropy offset. + +The ``CarnahanStarling`` EOS constructor has four arguments: ``gm1``, which is :math:`\gamma-1`; ``Cv``, the +specific heat :math:`C_V`; :math:`b`, the covolume; and :math:`q`, the internal energy offset. + +.. code-block:: cpp + + CarnahanStarling(Real gm1, Real Cv, Real b, Real q) + +Optionally, the reference state for the entropy calculation, +can be provided in the constructor via ``qp``, ``T0`` and ``P0``: + +.. code-block:: cpp + + CarnahanStarling(Real gm1, Real Cv, Real b, Real q, Real qp, Real T0, Real P0) + +Note that these parameters are provided solely for the entropy calculation. When +these values are not set, they will be the same as those returned by the +:code:`ValuesAtReferenceState()` function. However, if the entropy reference +conditions are given, the return values of the :code:`ValuesAtReferenceState()` +function will not be the same. + Gruneisen EOS ````````````` @@ -580,6 +668,9 @@ Given the inconsisetency in the temperature, we have made the choice **not** to expose the entropy for this EOS. **Requesting an entropy value will result in an error.** +If a linear :math:`U_s`-:math:`u_p` relation is enough for your problem, we recommend using the MGUsup +EOS described below. It is a complete EOS with consistent temperature. + Given a reference density, :math:`\rho_0`, we first parameterize the EOS using :math:`\eta` as a measure of compression given by @@ -603,6 +694,13 @@ in terms of :math:`\eta` as When the unitless user parameter :math:`b=0`, the Gruneisen parameter is of a form where :math:`\rho\Gamma =` constant in compression, i.e. when :math:`\eta > 0`. +If the unitless user parameter :math:`b=\Gamma_0`, the Gruneisen parameter is of a +form where :math:`\Gamma_0 =` constant in compression. These two limitig cases are +shown in the figure below. + +.. image:: ../SteinbergGammarho.pdf + :width: 500 + :alt: Figure: Demonstration of how the parameter b interpolated between two common approximations for Gamma The reference pressure along the Hugoniot is determined by @@ -751,6 +849,234 @@ is :math:`S_0`, and ``expconsts`` is a pointer to the constant array of length :math:`d_2` to :math:`d_{40}`. Expansion coefficients not used should be set to 0.0. +Mie-Gruneisen linear :math:`U_s`- :math:`u_p` EOS +````````````````````````````````````````````````` + +One of the most commonly-used EOS is the linear :math:`U_s`- :math:`u_p` version of the Mie-Gruneisen EOS. This EOS +uses the Hugoniot as the reference curve and is extensively used in shock physics. +This version implements the exact thermodynamic temperature on the Hugoniot and also adds an entropy. + +The pressure follows the traditional Mie-Gruneisen form, + +.. math:: + + P(\rho, e) = P_H(\rho) + \rho\Gamma(\rho) \left(e - e_H(\rho) \right), + +Here the subscript :math:`H` is a reminder that the reference curve is a +Hugoniot. :math:`\Gamma` is the Gruneisen parameter and the first approximation +is that :math:`\rho\Gamma(\rho)=\rho_0\Gamma(\rho_0)` +which is the same assumption as in the Gruneisen EOS when :math:`b=0`. + +The above is an incomplete equation of state because it only relates the +pressure to the density and energy, the minimum required in a solution to the +Euler equations. To complete the EOS and determine the temperature and entropy, a constant +heat capacity is assumed so that + +.. math:: + + T(\rho, e) = \frac{\left(e-e_H(\rho)\right)}{C_V} + T_H(\rho) + +Note the difference from the Gruneisen EOS described above. We still use a constant :math:`C_V`, +and it is usually taken at the reference temperature, but +we now extrapolate from the temperature on the Hugoniot, :math:`T_H(\rho)`, and not +from the reference temperature, :math:`T_0`. + +With this consistent temperature we can derive an entropy in a similar way as for the Vinet EOS. Using +thermodynamic derivatives we can show that + +.. math:: + + \Gamma \rho = \frac{\alpha B_T}{C_V} , + +and we arrive at + +.. math:: + + S(\rho,T) = S_0 - \Gamma(\rho_0)C_V \eta + {C_V} \ln \frac{T}{T_0} , + + +where :math:`\eta` is a measure of compression given by + +.. math:: + + \eta = 1 - \frac{\rho_0}{\rho}. + +This is convenient because :math:`\eta = 0` when :math:`\rho = \rho_0`, +:math:`\eta = 1` at the infinite density limit, and :math:`\eta = -\infty` at +the zero density limit. + +The pressure, energy, and temperature, on the Hugoniot are derived from the +shock jump conditions, + +.. math:: + + \rho_0 U_s &= \rho (U_s - u_p) \\ + P_H &= \rho_0 U_s u_p \ , + +assuming a linear :math:`U_s`- :math:`u_p` relation, + +.. math:: + + U_s = C_s + s u_p . + +Here :math:`U_s` is the shock velocity and :math:`u_p` is the particle +velocity. As is pointed out in the description of the Gruneisen EOS, +for many materials, the :math:`U_s`- :math:`u_p` relationship is roughly linear +so only this :math:`s` parameter is needed. The units for :math:`C_s` is velocity while +:math:`s` is unitless. Note that the parameter :math:`s` is related to the +fundamental derivative of shock physics as shown by `Mattsson-Wills `_. + +Solving the jump equations above gives that the reference pressure along the Hugoniot is determined by + +.. math:: + + P_H(\rho) = C_s^2 \rho_0 \frac{\eta}{\left(1 - s \eta \right)^2} . + +Note the singularity at :math:`s \eta = 1` which limits this model's validity to compressions +:math:`\eta << 1/s`. If your problem can be expected to have compressions of this order, you should use the PowerMG +EOS that is explicitely constructed for large compressions. +The assumption of linear :math:`U_s`- :math:`u_p` relation is simply not valid at large compressions. + +The energy along the Hugoniot is given by + +.. math:: + + E_H(\rho) = \frac{P_H \eta }{2 \rho_0} + E_0 . + +The temperature on the Hugoniot is hard to derive explicitely but with the help of Mathematica +we can solve + +.. math:: + :label: TH + + T_H(\rho) = T_0 e^{\Gamma(\rho_0) \eta} + \frac{e^{\Gamma(\rho_0) \eta}}{2 C_V \rho_0} + \int_0^\eta e^{-\Gamma(\rho_0) z} z^2 \frac{d}{dz} \left( \frac{P_H}{z}\right) dz + + +into the explicit formula + +.. math:: + + T_H(\rho) &= T_0 e^{\Gamma(\rho_0) \eta} + \frac{C_s^2}{2 C_V s^2} + \left[\frac{- s \eta}{(1 - s \eta)^2} + \left( \frac{\Gamma(\rho_0)}{s} - 3 \right) + \left( e^{\Gamma(\rho_0) \eta} - \frac{1}{(1-s \eta)}\right)\right. \\ + & \ \left. + e^{-\frac{\Gamma(\rho_0)}{s} (1-s \eta)} + \left( Ei(\frac{\Gamma(\rho_0)}{s}(1-s \eta))-Ei(\frac{\Gamma(\rho_0)}{s}) \right) + \left((\frac{\Gamma(\rho_0)}{s})^2 - 4 \frac{\Gamma(\rho_0)}{s} + 2 \right) \right] + +where :math:`Ei` is the exponential integral function. We replace the :math:`Ei` difference with a sum with cutoff +giving an error less than machine precision. For :math:`s \eta` close to :math:`0`, there are +severe cancellations in this formula and we use the expansion + +.. math:: + + {T_H}_{exp}(\rho) = T_0 e^{\Gamma(\rho_0) \eta} + \frac{C_s^2}{2 C_V s^2} + \left[ -2 \ln ( 1- s \eta) + \frac{s \eta}{(1 - s \eta)^2} ( 3 s \eta - 2) \right] \ . + + +The first omitted term in the expansion inside the square brackets is :math:`\Gamma(\rho_0) \eta^4 / 6`. This expansion is +in fact even better than the common approximation of replacing the full temperature on the Hugoniot with the temperature on the +isentrope, that is, the first term :math:`T_0 e^{\Gamma(\rho_0) \eta}`. + +.. image:: ../ApproxForTH.pdf + :width: 500 + :alt: Figure: Different approximations for the temperature on the Hugoniot. + +The constructor for the ``MGUsup`` EOS has the signature + +.. code-block:: cpp + + MGUsup(const Real rho0, const Real T0, const Real Cs, const Real s, const Real G0, + const Real Cv0, const Real E0, const Real S0) + +where +``rho0`` is :math:`\rho_0`, ``T0`` is :math:`T_0`, +``Cs`` is :math:`C_s`, ``s`` is :math:`s`, +``G0`` is :math:`\Gamma(\rho_0)`, ``Cv0`` is :math:`C_V`, +``E0`` is :math:`E_0`, and ``S0`` is :math:`S_0`. + +Mie-Gruneisen power expansion EOS +````````````````````````````````` +As we noted above, the assumption of a linear :math:`U_s`- :math:`u_p` relation is simply not valid at large compressions. At +Sandia National Laboratories Z-pinch machine, the compression is routinely so large that a new Mie-Gruneisen EOS was developped, +by `Robinson `_, that could handle these large compressions. The overall structure and motivation for approximations +are as described above; in compression it is only the formula for :math:`P_H`, and by extension :math:`T_H`, that differ. This +EOS is however modified in expansion to follow an isentrope instead of the invalid-in-expansion Hugoniot. + +In the PowerMG model the pressure on the Hugoniot in the compression region, :math:`\eta \geq 0` is expressed as a power series + +.. math:: + + P_H(\rho) = K_0 \eta \left( 1 + K_1 \eta + K_2 \eta^2 + K_3 \eta^3 + \cdots + K_M \eta^M \right) + +By expanding the MGUsup Hugoniot pressure into a power series in :math:`\eta` we see that we can recover the MGUsup results by setting + +.. math:: + + K_0 &=& C_s^2 \rho_0 \ \ \ \ \ \ \ \ & \\ + K_n &=& (n+1) s^n & \ \ \ \ \ \ n >= 1 + +In the figure below we have used :math:`M=20` with these coefficients and show how the divergence in the MGUsup pressure at :math:`\eta = \frac{1}{s}` is avoided in the PowerMG, making it more suitable for modeling high pressures. + +.. image:: ../PMGvsMGUsupPress.pdf + :width: 500 + :alt: Figure: Comparing Hugoniot pressure for PowerMG and MGUsup + +For :math:`\eta < 0`, that is, in expansion, the isentrope with a single :math:`K_0` is used until a user defined minimum pressure is obtained + +.. math:: + + P_H &= K_0 \eta& \ \ \ \ \ \ \ \ \ \ & \frac{P_{min}}{K_0} \leq \eta < 0 \\ + P_H &= P_{min} & \ \ \ \ \ \ \ \ \ \ & \eta < \frac{P_{min}}{K_0} + +If the user have not set :math:`P_{min}` or if a positive value has been given, a default value of :math:`P_{min} = -1000 K_0` is used. + +If we now insert the formula for :math:`P_H` in compression into equation :math:numref:`TH`, for :math:`\eta \geq 0` we arrive at + +.. math:: + + T_H = T_0 e^{\Gamma(\rho_0) \eta} + \frac{e^{\Gamma(\rho_0) \eta}}{2 C_V \rho_0} K_0 \left( K_1 I_2 + 2 K_2 I_3 + 3 K_3 I_4 + \cdots + M K_M I_{M+1} \right) + +where + +.. math:: + + I_n = \int_0^\eta e^{-\Gamma(\rho_0) z} z^{n-1} dz + +that can be rewritten in terms of the lower incomplete gamma function. For :math:`\eta < 0` the isentropic temperature is used, + +.. math:: + + T_H = T_0 e^{\Gamma(\rho_0) \eta} \ \ \ \ \ \ \ \ \ \ \eta < 0 \, . + +It has been verified that this temperature is following the black, true temperature line in the figure late in the MGUsup section in compression and the blue isentropic temperature in expansion. More information about how to implement :math:`T_H` into codes is given in `Robinson `_. + +For completeness we give :math:`E_H` as well, + +.. math:: + + E_H &= \frac{P_H \eta}{2 \rho_0} + E_0 & \ \ \ \ \ \ \ \ \ \ & \eta \geq 0 \\ + E_H &= \frac{K_0 \eta^2}{2 \rho_0} + E_0 & \ \ \ \ \ \ \ \ \ \ & \frac{P_{min}}{K_0} \leq \eta < 0 \\ + E_H &= \frac{K_0 \eta_{min}^2}{2 \rho_0} + E_0 + \frac{P_{min}}{\rho_0} (\eta - \eta_{min})& \ \ \ \ \ \ \ \ \ \ & \eta < \eta_{min} = \frac{P_{min}}{K_0} + +The constructor for the ``PowerMG`` EOS has the signature + +.. code-block:: cpp + + PowerMG(const Real rho0, const Real T0, const Real G0, const Real Cv0, const Real E0, + const Real S0, const Real Pmin, const Real *expconsts) + +where +``rho0`` is :math:`\rho_0`, ``T0`` is :math:`T_0`, +``G0`` is :math:`\Gamma(\rho_0)`, ``Cv0`` is :math:`C_V`, +``E0`` is :math:`E_0`, ``S0`` is :math:`S_0`, ``Pmin`` is :math:`P_{min}`, and +``expconsts`` is a pointer to the constant array of length +41 containing the expansion coefficients +:math:`K_0` to :math:`K_{40}`. Expansion coefficients not used should be set to +:math:`0.0`. + + + JWL EOS `````````` @@ -1014,17 +1340,44 @@ Here, there are four dimensionless parameters that are settable by the user, :math:`e_\mathrm{C}`, :math:`V_\mathrm{C}` and :math:`T_\mathrm{C}` are tuning parameters with units related to their non-subscripted counterparts. +Note that the energy zero (i.e. the reference energy) for the Davis products EOS +is arbitrary. For the isentrope to properly pass through the CJ state of a +reacting material, the energy release of the reaction needs to be accounted for +properly. If done external to the EOS, an energy source term is required in the +Euler equations. However, a common convention is to specify the reactants and +product EOS in a consistent way such that the reference energy corresponds to +the rest state of the material *before* it reacts. + +The energy at the CJ state can be calculated as + +.. math:: + + e_\mathrm{CJ} = \frac{P_0 + P_\mathrm{CJ}}{2(V_0 - V_\mathrm{CJ})}, + +relative to :math:`e = 0` at the reference state of the *reactants*. Therefore +the energy offset of the products EOS is given by + +.. math:: + + e_0 = e_S(V_\mathrm{CJ}) - e_\mathrm{CJ}. + +Practically, this means :math:`e_0` should be positive for any energetic material. + +To provide the energy offset to the Davis Products EOS, `the energy shift +modifier`_ should be used. Note that the convention there +is that the shift is positive, so :math:`-e_0` should be provided to the shift +modifier. + The constructor for the Davis Products EOS is .. code-block:: cpp DavisProducts(const Real a, const Real b, const Real k, const Real n, const Real vc, - const Real pc, const Real Cv, const Real E0) + const Real pc, const Real Cv) where ``a`` is :math:`a`, ``b`` is :math:`b`, ``k`` is :math:`k`, ``n`` is :math:`n`, ``vc`` is :math:`V_\mathrm{C}`, ``pc`` is -:math:`P_\mathrm{C}`, ``Cv`` is :math:`C_{V,0}`, and ``E0`` is -:math:`e_\mathrm{C}`. +:math:`P_\mathrm{C}`, ``Cv`` is :math:`C_{V,0}`. Spiner EOS ```````````` @@ -1153,7 +1506,7 @@ SAP Polynomial EOS `````````````````` This model is specific to the Safety Applications Project (SAP). It is -an imcomplete EOS, and is a simple analytical form used to fit +an incomplete EOS, and is a simple analytical form used to fit experimental data: .. math:: diff --git a/doc/sphinx/src/modifiers.rst b/doc/sphinx/src/modifiers.rst index 552b16940b..75e11310af 100644 --- a/doc/sphinx/src/modifiers.rst +++ b/doc/sphinx/src/modifiers.rst @@ -22,6 +22,8 @@ We list below the available modifiers and their constructors. The Shifted EOS ----------------- +.. _modifiers shifted EOS: + The shifted equation of state modifies zero point energy of an underlying model by some shift. So for example, it transforms diff --git a/doc/sphinx/src/using-closures.rst b/doc/sphinx/src/using-closures.rst index 2aced1b5d5..9675f3a518 100644 --- a/doc/sphinx/src/using-closures.rst +++ b/doc/sphinx/src/using-closures.rst @@ -3,131 +3,388 @@ Mixed Cell Closures ==================== -In Eulerian multi-material fluid simulations, a single grid point or -finite volume cell may have more than one material in it. In this -situation, one must decide how to compute thermodynamic quantities in -that cell. One choice, though not necessarily the optimal choice, is -to assume pressure-temperature equilibrium (PTE). This implies that there's -a single pressure in the cell and a single temperature, which are the -same for all materials. - -``singularity-eos`` provides several methods for finding a PTE -soluution. These methods differ in what they treat as independent -variables, and thus what precise system of equations they solve -for. However they all share some common characteristics. +In the single-material Euler equations, mass and energy are typically +evolved and the EOS is called to provide a pressure for the momentum equations. +When transitioning to a multi-material approach, a single velocity is typically +used and the Euler equations are solved with respect to the bulk fluid motion. +In this case, the pressure contribution to momentum isn't well-defined and in +principle each material could have its own pressure contribution to material +motion. Furthermore, the paritioning of volume and energy between the materials +in the flow is not well-defined either. + +As a result, a multi-material closure rule is needed to determine both how to +compute the pressure response of the flow and how to partition the volume and +energy between the individual materials. In this situation, one must decide how +to compute thermodynamic quantities in that cell for each material. Governing Equations and Assumptions ------------------------------------ -Given a set of :math:`N` materials ranging from :math:`i = 0` to -:math:`N-1`, each material can, in principle, have a distinct pressure -:math:`P_i`, a distinct temperature :math:`T_i`, a distinct material -density :math:`\rho_i`, and a distinct specific material energy -:math:`\varepsilon_i`. For some finite total volume :math:`V`, each -material also occupies some fraction of that volume given by the -*volume fraction* :math:`f_i` such that +In a general sense the mixed +material closure rule takes the form .. math:: - \sum_{i=0}^{N - 1} f_i = 1 + P_i = F(\rho, \epsilon, \mu_1, ..., \mu_i, ..., \mu_{N-1}) \\ + \rho_i = G(\rho, \epsilon, \mu_1, ..., \mu_i, ..., \mu_{N-1}) \\ + \epsilon_i = H(\rho, \epsilon, \mu_1, ..., \mu_i, ..., \mu_{N-1}) \\ + T_i = J(\rho, \epsilon, \mu_1, ..., \mu_i, ..., \mu_{N-1}) -The average density in a given material-occupied volume is +where each material has its own density, :math:`\rho_i`, and specific internal +energy, :math:`e_i`, as well as in principle its own pressure and temperature. +Each will be a function of the bulk density, :math:`\rho`, the bulk specific +internal energy, :math:`\epsilon`, and the mass fractions, :math:`\mu_j`, +of all other materials present. + +For convenience of minimizing input arguments though, the solvers in +``singularity-eos`` are typically posed in a different way that can sometimes be +unintuitive. + +For some finite total volume :math:`V`, each material occupies some fraction of +that volume given by the *volume fraction* +:math:`f_i` such that + +.. math:: + + \sum_{i=0}^{N - 1} f_i = f_\mathrm{tot}, + +where :math:`f_\mathrm{tot}` is the total fraction of the total volume being +considered (in principle, different closure models can be used for different +sets of materials). To consider the entire volume, :math:`f_\mathrm{tot}` can +simply be set to one. + +The average density, :math:`\overline{\rho}_i`, (i.e. mass per *total* volume) +for a material in the total volume is .. math:: - \bar{\rho} = \rho_i f_i + \overline{\rho}_i = \rho_i f_i, -and thus the density averaged over all materials is +where :math:`\rho_i` is the physical density (i.e. material mass per *material* +volume). It is important to note here that while the densities, :math:`\rho_i`, +and the volume fractions, :math:`f_i`, will vary as the closure model is +applied, the average densities, :math:`\overline{\rho}_i`, will all remain +constant, motiviating their internal use in the closure solvers. The total +density (mass of *participating* materials per total volume) is then .. math:: - \rho = \sum_{i=0}^{N - 1} \bar{\rho} = \sum_{i=0}^{N-1} \rho_i f_i + \rho = \sum_{i=0}^{N - 1} \overline{\rho}_i = \sum_{i=0}^{N-1} \rho_i f_i -Conservation of energy implies that +Similarly the energy can be summed in a similar way so that .. math:: - u = \rho \varepsilon = \sum_{i = 0}^{N - 1} \rho_i \varepsilon_i + u = \rho \epsilon = \sum_{i = 0}^{N - 1} \rho_i \epsilon_i + = \sum_{i = 0}^{N - 1} u_i -where :math:`u = E/V` is the energy density by volume for total energy -:math:`E` and total volume :math:`V`, and :math:`\varepsilon` is the -total specific internal energy within that volume. +where :math:`u` is the total internal energy density (internal energy per unit +volume). Similarly, :math:`u_i` is analagous to :math:`\overline{\rho}_i` in +that it is the internal energy for a material averaged over the entire control +volume. -The assumption of pressure equilibrium implies that +Internally, the closer models in ``singularity-eos`` operate on :math:`f_i`, +:math:`\overline{\rho}_i`, and :math:`u_i` as well as their total counterparts. +This is different than the forms stated at the beginning of this section so +that in essence the PTE solver has the form .. math:: - P = P_0 = P_1 = \ldots = P_{N - 1} + P_i = F(\epsilon, f_\mathrm{tot}, f_1, ..., f_i, ..., f_{N-1}, + \rho_1, ..., \rho_i, ..., \rho_{N-1}) \\ + \rho_i = G(\epsilon, f_\mathrm{tot}, f_1, ..., f_i, ..., f_{N-1}, + \rho_1, ..., \rho_i, ..., \rho_{N-1}) \\ + \epsilon_i = H(\epsilon, f_\mathrm{tot}, f_1, ..., f_i, ..., f_{N-1}, + \rho_1, ..., \rho_i, ..., \rho_{N-1}) \\ + T_i = J(\epsilon, f_\mathrm{tot}, f_1, ..., f_i, ..., f_{N-1}, + \rho_1, ..., \rho_i, ..., \rho_{N-1}) + + +The important nuance here is that **the volume fractions and densities are both +inputs and outputs** in the current ``singularity-eos`` formulation of the +closure models. From physics perspective this can be confusing, but from a code +perspective this limits the number of variables that need to be passed to the +PTE solver and provides a convenient way to specify an initial guess for the +closure state. + +.. warning:: + + The volume fractions and material densities must be consistent so that + + .. math:: + + \rho = \sum_{i=0}^{N - 1} \overline{\rho}_i = \sum_{i=0}^{N-1} \rho_i f_i + +.. note:: + + Since mass fraction information is encoded in the specification of the + component densities, :math:`\rho_i`, and component volume fractions, + :math:`f_i`, they must be consistent so that + + .. math:: + + \rho_i = \frac{\mu_i \rho}{f_i} + + .. math:: + + \sum\limits_{i=0}^{N-1} f_i = f_\mathrm{tot}. -where each pressure is computed as either + For most practical applications, a previous PTE state for the current masses + (i.e. from a previous timestep in a Lagrangian frame) or an appropriate + prediction of the new PTE state (i.e. from advected values in an Eulerian + frame) is usually available. This is usually the preferred input for the + volume fractions and densities provided that they are consistent with the + current mass fractions in the control volume. + + When a previous state is not available, an assuption must be made for how volume + is partitioned between the materials. The simplest (but perhaps not the most + effective) assumption is that volume is *equipartitioned* such that + + .. math:: + + f_i = \frac{1}{N}. + + It is important to note though that this may not be sufficient in *many* + cases. A better guess just use the mass fractions so that + + .. math:: + + f_i = \mu_i = \frac{\overline{\rho}_i}{\rho}, + + but this is really only valid when the materials have similar + compressibilities. A further improvement could be made by weighting the mass + fractions by the material bulk moduli to reflect the relative + compressibilities. + +Pressure-Temperature Equilibrium +-------------------------------- + +At present, ``singularity-eos`` focuses on several methods for finding a PTE +solution, i.e. one where the pressures and temperatures of the individual +materials are all the same. The methods presented differ in what they treat as +independent variables, and thus what precise system of equations they solve. +However they all share the above mathematical formulation. + +In essence, the PTE equations can be posed as two residual equations: .. math:: - P_i = P_i(\rho_i, T_i) + f_\mathrm{tot} - \sum\limits_{i=0}^{N-1} f_i = + \sum\limits_{i=0}^{N-1} f_i^*(x_i^*, y_i^*) - f_i(x_i, y_i) .. math:: - P_i = P_i(\rho_i, \varepsilon_i) + u_\mathrm{tot} - \sum\limits_{i=0}^{N-1} u_i = + \sum\limits_{i=0}^{N-1} u_i^*(x_i^*, y_i^*) - u_i(x_i, y_i) + +where the superscript :math:`^*` denotes the variables at the PTE state, +:math:`f` corresponds to the volume fractions, and :math:`u` to the energy +density (see the previous section for more information). In these equations, +:math:`x` and :math:`y` represent some choice of independent thermodynamic +variables. + +These are two non-linear residual equations that will need to be solved. In +``singularity-eos`` a Newton-Raphson method is used that first relies on +Taylor-expanding the equations about the equilibrium state in order to cast the +equations in terms of an update to the unknowns. The expansion about an +equilibrium state described by :math:`f_i^*(\rho_i, y_i)` and +:math:`u_i^*(\rho_i, y_i)` is + +.. math:: -depending on the treatment. + f_\mathrm{tot} - \sum\limits_{i=0}^{N-1} f_i(x_i, y_i) \approx + \sum\limits_{i=0}^{N-1} (x_i^* - x_i) + \left(\frac{\partial f_i}{\partial x_i}\right)_{y_i} + + \sum\limits_{i=0}^{N-1} (y_i^* - y_i) + \left(\frac{\partial f_i}{\partial y_i}\right)_{x_i} -In ``singularity-eos`` the :math:`N` volume fractions are treated as -unknowns, for which one must solve, and the fact that the volume -fractions sum to 1 implies one constraint. At this point, we have 1 -constraint and :math:`N` unknowns (the volume fractions). To guarantee -uniqueness (but not existence) of a PTE solution, we must find a way -to have at least as many equations as unknowns. There are several -choices: +.. math:: + + u - \sum\limits_{i=0}^{N-1} u_i(x_i, y_i) \approx + \sum\limits_{i=0}^{N-1} (x_i^* - x_i) + \left(\frac{\partial u_i}{\partial x_i}\right)_{y_i} + + \sum\limits_{i=0}^{N-1} (y_i^* - y_i) + \left(\frac{\partial u_i}{\partial y_i}\right)_{x_i}, + +providing a means to update the guess for the equilbrium state. Minor +manipulations are needed to recast the derivatives in terms of accessible +thermodynamic derivatives, and then these equations can be written in matrix +form to solve for the unknown distance away from the equilibrum state. At each +iteration of the Newton-Raphson solver, the derivatives are recomputed and a +new update is found until some tolerance is reached. When a good initial guess +is used (such as a previous PTE state), some algorithms may converge in +relatively few iterations. + +The choice of :math:`x` and :math:`y` is discussed below, but crucially it +determines the number of equations and unknowns needed to specify the system. +For example, if pressure, :math:`P`, and temperature, :math:`T`, are chosen, +then the subscripts are eliminated since we seek a solution where all materials +have the same temperature and pressure. In this formulation, there are two +equations and two unkowns, but due to the difficulty of inverting an +equation of state to be a function of pressure and temperature, +``singularity-eos`` does not have any PTE solvers that are designed to use +pressure and temperature as independent variables. + +Instead, all of the current PTE solvers in ``singularity-eos`` are cast in terms +of volume fraction and some other independent variable. Using material volume +fractions introduces :math:`N - 1` additional unknowns since all but one of the +volume fractions are independent from each other. The assumption of pressure +equilibrium naturally leads to the addition of :math:`N - 1` residual equations +of the form + +.. math:: + + P_i(f_i, y_i) - P_j(f_j, y_j) = 0, + + +These can also be written as a Taylor expansion about the equilibrium state such +that + +.. math:: + + P_i(f_i, y_j) - P_j(f_j, y_j) + = (f^*_i - f_i) \left(\frac{\partial P_i}{\partial f_i}\right)_{y_i} + + (y^*_i - y_i) \left(\frac{\partial P_i}{\partial y_i}\right)_{f_i} \\ + - (f^*_j - f_j) \left(\frac{\partial P_j}{\partial f_j}\right)_{y_j} + - (y^*_j - y_j) \left(\frac{\partial P_j}{\partial y_j}\right)_{f_j}, + +where the equations are typically written such that :math:`j = i + 1`. Since the +equlibrium pressure is the same for both materials, the term cancels out and +the material pressures are left. + + +Formulating the closure equations in terms of volume fractions instead of +densities has the benefit of allowing the volume constraint to be written in +terms of just the volume fractions: + +.. math:: + + f_\mathrm{tot} - \sum\limits_{i=0}^{N-1} f_i = + \sum\limits_{i=0}^{N-1} (f_i^* - f_i). + +The EOS only returns derivatives in terms of density though, so a the density +derivatives must be transformed to volume fraction derivatives via + +.. math:: + + \left(\frac{\partial Q}{\partial f_i}\right)_X + = - \frac{\rho_i^2}{\rho}\left(\frac{\partial Q}{\partial \rho_i}\right)_X, + +were :math:`Q` and :math:`X` are arbitrary thermodynamic variables. At this +point, there are :math:`N + 1` equations and unknowns in the PTE sover. The +choice of the second independent variable is discussed below and has +implications for both the number of additional unknowns and the stability of the +method. The Density-Energy Formulation ---------------------------------- +'''''''''''''''''''''''''''''' -One choice is to treat volume fractions and material energies as -independent quantities. The material energies provide :math:`N` more -unknowns. The equality of pressures provides :math:`N-1` additional -constraints. Additionally, the euqality of material temperatures, evaluated as +One choice is to treat volume fractions and material energies as independent +quantities, but the material energies provide :math:`N - 1` additional +unknowns. The additional degrees of freedom are satisfied by requiring that the +material temperatures be equal. As a result, we add :math:`N - 1` residual +equations of the form .. math:: - T = T_0(\rho_0, \varepsilon_0) = T_1(\rho_1, \varepsilon_1) = \ldots = T_{N-1}(\rho_{N-1},\varepsilon_{N-1}) + T_i(\rho_i, \epsilon_i) - T_j(\rho_j, \epsilon_j) = 0. + +Again Taylor expanding about the equilibirum state, this results in a set of +equations of the form -provides :math:`N-1` additional constraints. Finally, conservation of -energy provides one more constraint. In the end we have :math:`2 N` -constraints and :math:`2 N` unknowns. +.. math:: + + T_i(f_i, \epsilon_i) - T_j(f_j, \epsilon_j) + = (f^*_i - f_i) \left(\frac{\partial T_i}{\partial f_i}\right)_{\epsilon_i} + + (\epsilon^*_i - \epsilon_i) \ + \left(\frac{\partial T_i}{\partial \epsilon_i}\right)_{f_i} \\ + - (f^*_j - f_j) \left(\frac{\partial T_j}{\partial f_j}\right)_{\epsilon_j} + - (\epsilon^*_j - \epsilon_j) + \left(\frac{\partial T_j}{\partial \epsilon_j}\right)_{f_j} + +Here there are a total number of :math:`2N` equations and unknowns, which +results in a fairly large matrix to invert when many materials are present in a +cell. Further, the density-energy derivatives may require inversion of any EOS +with density and temperature as the natural variables. In the case of tabular +EOS, an iterative inversion step may be required to find the density-energy +state by iterating on temperature; there may also be a loss of accuracy in the +derivatives depending on how they are calculated. + +In general, the density-temperature formulation of the PTE solver seems to be +more stable and performant and is usually preferrred to this formulation. In the code this is referred to as the ``PTESolverRhoU``. The Density-Temperature Formulation ------------------------------------- +''''''''''''''''''''''''''''''''''' -Another choice is to treat the temperature as an independent -variable. Then the assumption of PTE implies that +Another choice is to treat the temperature as an independent variable, requiring +no additional equations. The energy residual equation then takes the form .. math:: - T = T_0 = T_1 = \ldots = T_{N - 1} + u - \sum\limits_{i=0}^{N-1} u_i(f_i, T) \approx + \sum\limits_{i=0}^{N-1} (f_i^* - f_i) + \left(\frac{\partial u_i}{\partial f_i}\right)_{T} + + (T^* - T)\sum\limits_{i=0}^{N-1} + \left(\frac{\partial u_i}{\partial T}\right)_{f_i}, + +where the temperature difference can be factored out of the sum since it doesn't +depend on material index. + +In the code this is referred to as the ``PTESolverRhoT``. + +Fixed Pressure or Temperature +""""""""""""""""""""""""""""" + +For initialization, the energy of a mixed material region is usually unknown +while the density, mass fractions, and either temperature or pressure *are* +known. To find the energy, a PTE solve is required, but with the added +constraint of the fixed pressure or temperature. + +Fixed temperature +^^^^^^^^^^^^^^^^^ -which leads to a single additional unknown, the temperature -:math:`T`. The equality of pressure, now computed as +When the temperature and total density are known, the equilibrium pressure and +the component densities are unknown. This requires a total of :math:`N` +equations and unknowns. Since the total energy is unknown, it can be dropped +from the contraints leaving just the :math:`N - 1` pressure equality equations +and the volume fraction sum constraint. The pressure residuals can then be +simplified to be .. math:: - P_0(\rho_0, T) = P_1(\rho_1, T) = \ldots = P_{N-1}(\rho_{N-1}, T) + P_i(f_i, T) - P_j(f_j, T) + = (f^*_i - f_i) \left(\frac{\partial P_i}{\partial f_i}\right)_{T} + - (f^*_j - f_j) \left(\frac{\partial P_j}{\partial f_j}\right)_{T} -provides an additional :math:`N-1` constraints. Conservation of -energy, now computed as +In the code this is referred to as the ``PTESolverFixedT``. + +Fixed pressure +^^^^^^^^^^^^^^ + +When the pressure and total density are known, the procedure is slightly more +complicated. Since the pressure is known but the independent variables are +density and temperature, there are :math:`N + 1` unknowns for the component +densities and the unknown equilibrium temperature. + +Once again, the energy constraint is dropped since the energy is unknown, but +since the equilibrium pressure is a *specified* quantity, the pressure residual +equations must be modified to take the form .. math:: - u = \sum_{i=}^{N-1} \rho_i \varepsilon_i(\rho_i, T) + P_i^*(f^*_i, T) - P_i(f_i, T) + = (f^*_i - f_i) \left(\frac{\partial P_i}{\partial f_i}\right)_{T} + - (T^* - T) \left(\frac{\partial P_i}{\partial T}\right)_{f_i}. -provides another constraint. This leads to :math:`N+1` constraints and -:math:`N+1` unknowns. +Note that this results in :math:`N` equations for each of the individual +material pressures. -In the code this is referred to as the ``PTESolverRhoT``. +In the code this is referred to as the ``PTESolverFixedP``. Using the Pressure-Temperature Equilibrium Solver --------------------------------------------------- +''''''''''''''''''''''''''''''''''''''''''''''''' The PTE machinery is implemented in the ``singularity-es/closure/mixed_cell_models.hpp`` header. It is @@ -167,6 +424,24 @@ objects for each equation of state, similar to the vector API for a given EOS. Here the indexers/vectors are not over cells, but materials. +.. warning:: + + It bears repeating: **both the volume fractions and densities act as inputs + and outputs**. They are used to define the internal :math:`\overline + {\rho}_i` variables at the beginning of the PTE solve. The volume fractions + and densities at the end of the PTE solve will represent those for the new + PTE state. It's important to note that :math:`\overline{\rho}_i` remain + constant throughout the calculation. + +.. warning:: + + The PTE solvers **require** that all input densities and volume fractions + are non-zero. As a result, ``nmat`` refers to the number of *participating* + materials. The user is encouraged to wrap their data arrays using an + ``Indexer`` concept where, for example, three paricipating PTE materials + might be indexed as 5, 7, 20 in the material arrays. This requires overloading + the square bracket operator to map from PTE idex to material index. + The constructor for the ``PTESolverRhoT`` is of the form .. code-block:: cpp @@ -185,11 +460,11 @@ total specific internal energy in the problem, ``rho`` is an indexer over densities, one per material. ``vfract`` is an indexer over volume fractions, one per material. ``sie`` is an indexer over temperatures, one per material. ``press`` is an indexer over pressures, one per -material. ``lambda`` is an indexer over lambda arrays, one ``Real *`` -object per material. ``scratch`` is a pointer to pre-allocated scratch -memory, as described above. It is assumed enough scratch has been -allocated. Finally, the optional argument ``Tguess`` allows for host -codes to pass in an initial temperature guess for the solver. For more +material. ``lambda`` is an indexer over lambda arrays, one per +material. ``scratch`` is a pointer to pre-allocated scratch memory, as +described above. It is assumed enough scratch has been allocated. +Finally, the optional argument ``Tguess`` allows for host codes to +pass in an initial temperature guess for the solver. For more information on initial guesses, see the section below. The constructor for the ``PTESolverRhoU`` has the same structure: @@ -223,7 +498,7 @@ For an example of the PTE solver machinery in use, see the ``test_pte.cpp`` file in the tests directory. Initial Guesses for PTE Solvers ------------------------------------- +''''''''''''''''''''''''''''''' As is always the case when solving systems of nonlinear equations, good initial guesses are important to ensure rapid convergence to the solution. For the PTE diff --git a/doc/sphinx/src/using-eos.rst b/doc/sphinx/src/using-eos.rst index 7f1d975863..83bdde1d35 100644 --- a/doc/sphinx/src/using-eos.rst +++ b/doc/sphinx/src/using-eos.rst @@ -77,7 +77,7 @@ method. ``get`` is templated and type deduction is not possible. You must specify the type of the class you're pulling out of the variant. For example: -.. code-block:: +.. code-block:: cpp auto my_ideal_gas = my_eos.get(); @@ -91,7 +91,7 @@ The EOS model also allows some host-side introspection. The method returns a string representing the equation of state an ``EOS`` object currently is. For example: -.. code-block:: +.. code-block:: cpp auto tpe_str = my_ideal_gas.EosType(); // prints "IdealGas" @@ -158,20 +158,16 @@ method, which can be called as, e.g., eos.Finalize(); -Vector and Scalar API, Accessors ---------------------------------- +Accessors and Indexers +----------------------- -Most ``EOS`` methods have both scalar and vector overloads, where the -scalar version returns a value, and the vector version modifies an -array. By default the vector version is called from host on device (if -``singularity-eos`` was compiled for device). - -The vector API is templated to accept *accessors*. An accessor is any -object with a square bracket operator. One-dimensional arrays, -pointers, and ``std::vector`` are all examples of what we call -an accessor. However, the value of an accessor is it doesn't have to -be an array. You can create an accessor class that wraps your -preferred memory layout, and ``singularity-eos`` will handle it +Many functions in ``singularity-eos`` accept **accessors**, also +called **indexers**. An accessor is any object with a square bracket +operator. One-dimensional arrays, pointers, and +``std::vector`` are all examples of what we call an +accessor. However, the value of an accessor is it doesn't have to be +an array. You can create an accessor class that wraps your preferred +memory layout, and ``singularity-eos`` will handle it appropriately. An accessor that indexes into an array with some stride might look like this: @@ -186,8 +182,20 @@ might look like this: int stride_; }; -We do note, however, that vectorization may suffer if your underlying -data structure is not contiguous in memory. +The Vector API and the ``lambda`` optional arguments all use +accessors, as discussed below. + +Vector and Scalar API +---------------------- + +Most ``EOS`` methods have both scalar and vector overloads, where the +scalar version returns a value, and the vector version modifies an +array. By default the vector version is called from host on device (if +``singularity-eos`` was compiled for device). + +The vector API is templated to accept accessors. We do note, however, +that vectorization may suffer if your underlying data structure is not +contiguous in memory. .. _eospac_vector: @@ -246,7 +254,7 @@ decorated so that it may be evaluated on either host or device, depending on desired use-case. Alternatively, you may use an anonymous function with an `auto` argument as the input, e.g., -.. code-block:: +.. code-block:: cpp // equivalent to [=], but with device markings eos.Evaluate(PORTABLE_LAMBDA(auto eos) { /* my code snippet */ }); @@ -339,12 +347,16 @@ Lambdas and Optional Parameters -------------------------------- Most methods for ``EOS`` objects accept an optional ``lambda`` -parameter, which is a ``Real *``. Unless specified in :ref:`the -models section `, this parameter does nothing. However, some -models require or benefit from additional information. For example -models with internal root finds can leverage initial guesses and -models with composition mixing parameters may need additional input to -return a meaningful state. +parameter, which is an accessor as discussed above. ``lambda[i]`` +should return a real number unless ``lambda==nullptr``. Unless +specified in :ref:`the models section `, this parameter does +nothing, and the default type is ``Real*`` with a default value of +``nullptr`` + +However, some models require or benefit from additional +information. For example models with internal root finds can leverage +initial guesses and models with composition mixing parameters may need +additional input to return a meaningful state. ``EOS`` models are introspective and can provide the desired/required size of the lambda array with: @@ -352,8 +364,8 @@ size of the lambda array with: .. cpp:function:: int EOS::nlambda() which is the desired size of the ``lambda`` array per scalar call. For -vector calls, there should be one such array per grid point. An -accessor for ``lambda`` should return a ``Real *`` pointer at each +vector calls, there should be one such accessor per grid point. A +vector accessor for ``lambda`` should return an accessor at each index. A trivial example of such an indexer for ``lambda`` might be the null indexer: @@ -488,11 +500,18 @@ currently: * ``thermalqs::temperature`` * ``thermalqs::specific_heat`` * ``thermalqs::bulk_modulus`` +* ``thermalqs::do_lambda`` * ``thermalqs::all_values`` however, most EOS models only specify that they prefer density and temperature or density and specific internal energy. +.. note:: + + The ``thermalqs::do_lambda`` flag is a bit special. It specifies that + eos-specific operations are to be performed on the additional + quantities passed in through the ``lambda`` variable. + .. _eos builder section: EOS Builder @@ -544,13 +563,17 @@ cgs. Unless specified, all functions work on device, if the code is compiled appropriately. The exceptions are constructors, ``GetOnDevice``, and ``Finalize``, all of which are host-only. -.. cpp:function:: Real TemperatureFromDensityInternalEnergy(const Real rho, const Real sie, Rela &lambda = nullptr) const; +.. code-block:: cpp + + template + Real TemperatureFromDensityInternalEnergy(const Real rho, const Real sie, + Indexer_t &&lambda = nullptr) const; Returns temperature in Kelvin. Inputs are density in :math:`g/cm^3` and specific internal energy in :math:`erg/g`. The vector equivalent of this function is -.. code-block:: +.. code-block:: cpp template inline void @@ -567,39 +590,63 @@ parameter is always last in the function signature. As they are all almost exactly analogous to their scalar counterparts, we will mostly not list the vector functions here. -.. cpp:function:: Real InternalEnergyFromDensityTemperature(const Real rho, const Real temperature, Real *lambda=nullptr) const; +.. code-block:: cpp + + template + Real InternalEnergyFromDensityTemperature(const Real rho, const Real temperature, + Indexer_t &&lambda = nullptr) const; returns specific internal energy in :math:`erg/g` given a density in :math:`g/cm^3` and a temperature in Kelvin. -.. cpp:function:: Real PressureFromDensityTemperature(const Real rho, const Real temperature, Real *lambda = nullptr) const; +.. code-block:: cpp + + template + Real PressureFromDensityTemperature(const Real rho, const Real temperature, + Indexer_t &&lambda = nullptr) const; returns pressure in Barye given density in :math:`g/cm^3` and temperature in Kelvin. -.. cpp:function:: Real PressureFromDensityInternalEnergy(const Real rho, const Real temperature, Real *lambda = nullptr) const; +.. code-block:: cpp + + template + Real PressureFromDensityInternalEnergy(const Real rho, const Real temperature, + Indexer_t &&lambda = nullptr) const; returns pressure in Barye given density in :math:`g/cm^3` and specific internal energy in :math:`erg/g`. -.. cpp:function:: Real SpecificHeatFromDensityTemperature(const Real rho, const Real temperature, Real *lambda = nullptr) const; +.. code-block:: cpp + + template + Real SpecificHeatFromDensityTemperature(const Real rho, const Real temperature, + Indexer_t &&lambda = nullptr) const; returns specific heat capacity at constant volume, in units of :math:`erg/(g K)` in terms of density in :math:`g/cm^3` and temperature in Kelvin. -.. cpp:function:: Real SpecificHeatFromDensityInternalEnergy(const Real rho, const Real sie, Real *lambda = nullptr) const; +.. code-block:: cpp + + template + Real SpecificHeatFromDensityInternalEnergy(const Real rho, const Real sie, + Indexer_t &&lambda = nullptr) const; returns specific heat capacity at constant volume, in units of :math:`erg/(g K)` in terms of density in :math:`g/cm^3` and specific internal energy in :math:`erg/g`. -.. cpp:function:: Real BulkModulusFromDensityTemperature(const Real rho, const Real temperature, Real *lambda = nullptr) const; +.. code-block:: cpp + + template + Real BulkModulusFromDensityTemperature(const Real rho, const Real temperature, + Indexer_t &&lambda = nullptr) const; returns the the bulk modulus .. math:: - B_s = (\partial P/\partial \rho)_s + B_s = \rho (\partial P/\partial \rho)_s in units of :math:`g cm^2/s^2` given density in :math:`g/cm^3` and temperature in Kelvin. For most material models, the square of the @@ -620,12 +667,20 @@ enthalpy by volume. The sound speed may also differ for, e.g., porous models, where the pressure is less directly correlated with the density. -.. cpp:function:: Real BulkModulusFromDensityInternalEnergy(const Real rho, const Real sie, Real *lambda = nullptr) const; +.. code-block:: cpp + + template + Real BulkModulusFromDensityInternalEnergy(const Real rho, const Real sie, + Indexer_t &&lambda = nullptr) const; returns the bulk modulus in units of :math:`g cm^2/s^2` given density in :math:`g/cm^3` and specific internal energy in :math:`erg/g`. -.. cpp:function:: Real GruneisenParamFromDensityTemperature(const Real rho, const Real temperature, Real *lambda = nullptr) const; +.. code-block:: cpp + + template + Real GruneisenParamFromDensityTemperature(const Real rho, const Real temperature, + Indexer_t &&lambda = nullptr) const; returns the unitless Gruneisen parameter @@ -635,14 +690,23 @@ returns the unitless Gruneisen parameter given density in :math:`g/cm^3` and temperature in Kelvin. -.. cpp:function:: Real GruneisenParamFromDensityInternalEnergy(const Real rho, const Real sie, Real *lambda = nullptr) const; +.. code-block:: cpp + + template + Real GruneisenParamFromDensityInternalEnergy(const Real rho, const Real sie, + Indexer_t &&lambda = nullptr) const; returns the unitless Gruneisen parameter given density in :math:`g/cm^3` and specific internal energy in :math:`erg/g`. The function -.. cpp:function:: void ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, Real &bmod, Real &dpde, Real &dvdt, Real *lambda = nullptr) const; +.. code-block:: cpp + + template + void ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, + Real &cv, Real &bmod, Real &dpde, Real &dvdt, + Indexer_t &&lambda = nullptr) const; fills the density, temperature, specific internal energy, pressure, and thermodynamic derivatives a specifically chosen characteristic @@ -653,7 +717,13 @@ representative energy and density scale. The function -.. cpp:function:: void FillEos(Real &rho, Real &temp, Real &energy, Real &press, Real &cv, Real &bmod, const unsigned long output, Real *lambda = nullptr) const; +.. code-block:: cpp + + template + void FillEos(Real &rho, Real &temp, Real &energy, + Real &press, Real &cv, Real &bmod, + const unsigned long output, + Indexer_t &&lambda = nullptr) const; is a a bit of a special case. ``output`` is a bitfield represented as an unsigned 64 bit number. Quantities such ``pressure`` and diff --git a/eospac-wrapper/CMakeLists.txt b/eospac-wrapper/CMakeLists.txt index fc5c7fabec..a832dce41f 100644 --- a/eospac-wrapper/CMakeLists.txt +++ b/eospac-wrapper/CMakeLists.txt @@ -21,6 +21,7 @@ list(APPEND EOSWRAPPER_SRCS eospac_wrapper.cpp) add_library(eospac-wrapper ${EOSWRAPPER_SRCS} ${EOSWRAPPER_HEADERS} ) +add_library(singularity-eos::singularity-eos_EospacWrapper ALIAS eospac-wrapper) target_include_directories(eospac-wrapper PUBLIC @@ -47,5 +48,5 @@ install( ) install( - TARGETS eospac-wrapper EXPORT singularity-eosTargets DESTINATION ${CMAKE_INSTALL_LIBDIR} + TARGETS eospac-wrapper EXPORT singularity-eos_Common DESTINATION ${CMAKE_INSTALL_LIBDIR} ) diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index b56372595b..c367b8b51e 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -17,7 +17,7 @@ add_executable(get_sound_speed_press target_link_libraries(get_sound_speed_press PRIVATE singularity-eos::singularity-eos) -if(SINGULARITY_USE_EOSPAC) +if(SINGULARITY_USE_EOSPAC AND SINGULARITY_USE_SPINER_WITH_HDF5) add_executable(get_sesame_state get_sesame_state.cpp) target_link_libraries(get_sesame_state PRIVATE diff --git a/example/get_sound_speed_press.cpp b/example/get_sound_speed_press.cpp index 9ecbf4a283..6c25221048 100644 --- a/example/get_sound_speed_press.cpp +++ b/example/get_sound_speed_press.cpp @@ -91,37 +91,9 @@ int main() { constexpr double gm1 = 0.6; constexpr double Cv = 2; - // We initialize the eos two ways to show how it can be done // First initialize the EOS the "easy" way: EOS eos1 = IdealGas(gm1, Cv); - // The EOS Builder automates building an eos with modifiers, such as - // shift and scale by worrying about the combinatorics/switch - // statements, etc, for you. We'll initialize a shifted/scaled EOS - // with shift 0 and scale 1 to show you how it's done - constexpr double shift = 0; - constexpr double scale = 1; - - // Eos builder requires a type specification, - // and then for each modifier, it requires a set of parameters, - // which are implemented as a variatic dictionary. - // - // This is equivalent to - // EOS eos2 = Shifted(Scaled(IdealGas(gm1, Cv), scale), shift); - EOSBuilder::EOSType type = EOSBuilder::EOSType::IdealGas; - EOSBuilder::modifiers_t modifiers; // this is a dictionary - EOSBuilder::params_t base_params, shifted_params, scaled_params; // so are these - base_params["Cv"].emplace( - Cv); // base params is the parameters of the underlying eos - base_params["gm1"].emplace(gm1); - shifted_params["shift"].emplace( - shift); // these are the parameters for the modifiers - scaled_params["scale"].emplace(scale); // you use strings for the variable names - // for each modifier put the relevant params in the modifiers object - modifiers[EOSBuilder::EOSModifier::Shifted] = shifted_params; - modifiers[EOSBuilder::EOSModifier::Scaled] = scaled_params; - EOS eos2 = EOSBuilder::buildEOS(type, base_params, modifiers); // build the builder - // If you're on device, you need to call // eos1.GetOnDevice(); // to call the EOS on device @@ -155,7 +127,6 @@ int main() { // This usually only does anything if you're on device, but for GPU-data it // will call the appropriate destructor. eos1.Finalize(); - eos2.Finalize(); return 0; } diff --git a/config/singularity-eosCMakeConfig.cmake.in b/example/plugin/CMakeLists.txt similarity index 73% rename from config/singularity-eosCMakeConfig.cmake.in rename to example/plugin/CMakeLists.txt index 1ed10cc04f..c7f4340673 100644 --- a/config/singularity-eosCMakeConfig.cmake.in +++ b/example/plugin/CMakeLists.txt @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------# -# © 2021-2023. Triad National Security, LLC. All rights reserved. This +# © 2024. Triad National Security, LLC. All rights reserved. This # program was produced under U.S. Government contract 89233218CNA000001 # for Los Alamos National Laboratory (LANL), which is operated by Triad # National Security, LLC for the U.S. Department of Energy/National @@ -12,4 +12,11 @@ # publicly and display publicly, and to permit others to do so. #------------------------------------------------------------------------------# -set(singularity-eosCMake_PREFIX @CMAKE_INSTALL_PREFIX@/share/singularity-eos/cmake) +# Add the header file to the list of headers +register_headers(PLUGIN dust dust.hpp dust_variant.hpp) + +# Register this test to be built in the test suite +register_tests(tst/test_dust.cpp) + +# Export lists to parent scope +export_plugin() diff --git a/example/plugin/dust/dust.hpp b/example/plugin/dust/dust.hpp new file mode 100644 index 0000000000..03c737d4ec --- /dev/null +++ b/example/plugin/dust/dust.hpp @@ -0,0 +1,144 @@ +//------------------------------------------------------------------------------ +// © 2024. Triad National Security, LLC. All rights reserved. This +// program was produced under U.S. Government contract 89233218CNA000001 +// for Los Alamos National Laboratory (LANL), which is operated by Triad +// National Security, LLC for the U.S. Department of Energy/National +// Nuclear Security Administration. All rights in the program are +// reserved by Triad National Security, LLC, and the U.S. Department of +// Energy/National Nuclear Security Administration. The Government is +// granted for itself and others acting on its behalf a nonexclusive, +// paid-up, irrevocable worldwide license in this material to reproduce, +// prepare derivative works, distribute copies to the public, perform +// publicly and display publicly, and to permit others to do so. +//------------------------------------------------------------------------------ + +#ifndef _EXAMPLE_PLUGIN_DUST_ +#define _EXAMPLE_PLUGIN_DUST_ + +// Ports-of-call +#include + +// Base stuff +#include +#include +#include +#include + +namespace singularity { + +using namespace eos_base; + +class Dust : public EosBase { + public: + PORTABLE_INLINE_FUNCTION Dust() : _Cv(1) {} + PORTABLE_INLINE_FUNCTION Dust(Real Cv) : _Cv(Cv) {} + + Dust GetOnDevice() { return *this; } + inline void Finalize() {} + + PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy( + const Real rho, const Real sie, Real *lambda = nullptr) const { + return sie / _Cv; + } + PORTABLE_INLINE_FUNCTION Real InternalEnergyFromDensityTemperature( + const Real rho, const Real temperature, Real *lambda = nullptr) { + return _Cv * temperature; + } + PORTABLE_INLINE_FUNCTION Real PressureFromDensityTemperature( + const Real rho, const Real temperature, Real *lambda = nullptr) const { + return 0; + } + PORTABLE_INLINE_FUNCTION Real PressureFromDensityInternalEnergy( + const Real rho, const Real sie, Real *lambda = nullptr) const { + return 0; + } + PORTABLE_INLINE_FUNCTION Real + MinInternalEnergyFromDensity(const Real rho, Real *lambda = nullptr) const { + return 0.0; + }; + + PORTABLE_INLINE_FUNCTION Real EntropyFromDensityTemperature( + const Real rho, const Real temperature, Real *lambda = nullptr) const { + return 0; + } + PORTABLE_INLINE_FUNCTION Real EntropyFromDensityInternalEnergy( + const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real temp = TemperatureFromDensityInternalEnergy(rho, sie, lambda); + return 0; + } + PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityTemperature( + const Real rho, const Real temperature, Real *lambda = nullptr) const { + return _Cv; + } + PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityInternalEnergy( + const Real rho, const Real sie, Real *lambda = nullptr) const { + return _Cv; + } + PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityTemperature( + const Real rho, const Real temperature, Real *lambda = nullptr) const { + return 0; + } + PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityInternalEnergy( + const Real rho, const Real sie, Real *lambda = nullptr) const { + return 0; + } + PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityTemperature( + const Real rho, const Real temperature, Real *lambda = nullptr) const { + return 0; + } + PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityInternalEnergy( + const Real rho, const Real sie, Real *lambda = nullptr) const { + return 0; + } + PORTABLE_INLINE_FUNCTION void FillEos(Real &rho, Real &temp, Real &energy, Real &press, + Real &cv, Real &bmod, const unsigned long output, + Real *lambda = nullptr) const { + press = 0; + bmod = 0; + cv = _Cv; + if (output & thermalqs::density) { + UNDEFINED_ERROR; + } + if (output & thermalqs::specific_internal_energy) { + if (!(output & thermalqs::temperature)) { + UNDEFINED_ERROR; + } + energy = _Cv * temp; + } + if (output & thermalqs::temperature) { + if (!(output & thermalqs::specific_internal_energy)) { + temp = energy / _Cv; + } + } + }; + PORTABLE_INLINE_FUNCTION + void ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, + Real &bmod, Real &dpde, Real &dvdt, + Real *lambda = nullptr) const { + rho = temp = sie = 1; + press = bmod = dpde = 0; + dvdt = 0; + } + SG_ADD_BASE_CLASS_USINGS(Dust) + + PORTABLE_INLINE_FUNCTION int nlambda() const noexcept { return 0; } + static constexpr unsigned long PreferredInput() { return _preferred_input; } + static inline unsigned long scratch_size(std::string method, unsigned int nelements) { + return 0; + } + static inline unsigned long max_scratch_size(unsigned int nelements) { return 0; } + PORTABLE_INLINE_FUNCTION void PrintParams() const { + printf("Dust Parameters:\nCv = %g\n", _Cv); + } + static std::string EosType() { return std::string("Dust"); } + static std::string EosPyType() { return EosType(); } + + private: + Real _Cv = 1; + static constexpr const unsigned long _preferred_input = + thermalqs::density | thermalqs::specific_internal_energy | thermalqs::temperature; +}; + +} // namespace singularity + +#endif // _EXAMPLE_PLUGIN_DUST_ diff --git a/singularity-eos/eos/eos.hpp b/example/plugin/dust/dust_variant.hpp similarity index 81% rename from singularity-eos/eos/eos.hpp rename to example/plugin/dust/dust_variant.hpp index 69a839235a..cba779a537 100644 --- a/singularity-eos/eos/eos.hpp +++ b/example/plugin/dust/dust_variant.hpp @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// © 2021-2023. Triad National Security, LLC. All rights reserved. This +// © 2024. Triad National Security, LLC. All rights reserved. This // program was produced under U.S. Government contract 89233218CNA000001 // for Los Alamos National Laboratory (LANL), which is operated by Triad // National Security, LLC for the U.S. Department of Energy/National @@ -12,12 +12,12 @@ // publicly and display publicly, and to permit others to do so. //------------------------------------------------------------------------------ -#ifndef _SINGULARITY_EOS_EOS_EOS_HPP_ -#define _SINGULARITY_EOS_EOS_EOS_HPP_ +#ifndef _EXAMPLE_PLUGIN_DUST_DUST_VARIANT_HPP_ +#define _EXAMPLE_PLUGIN_DUST_DUST_VARIANT_HPP_ -#include "stdio.h" #include #include +#include #include #include #include @@ -33,25 +33,9 @@ #include // EOS models -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include -// Modifiers -#include -#include -#include -#include -#include +#include namespace singularity { @@ -67,8 +51,8 @@ using singularity::variadic_utils::transform_variadic_list; // all eos's static constexpr const auto full_eos_list = - tl) { using EOS = typename decltype(tl_to_Variant(combined_list))::vt; } // namespace singularity -#endif // _SINGULARITY_EOS_EOS_EOS_HPP_ +#endif // _EXAMPLE_PLUGIN_DUST_DUST_VARIANT_HPP_ diff --git a/example/plugin/tst/test_dust.cpp b/example/plugin/tst/test_dust.cpp new file mode 100644 index 0000000000..f8ea0ddf50 --- /dev/null +++ b/example/plugin/tst/test_dust.cpp @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// © 2024. Triad National Security, LLC. All rights reserved. This +// program was produced under U.S. Government contract 89233218CNA000001 +// for Los Alamos National Laboratory (LANL), which is operated by Triad +// National Security, LLC for the U.S. Department of Energy/National +// Nuclear Security Administration. All rights in the program are +// reserved by Triad National Security, LLC, and the U.S. Department of +// Energy/National Nuclear Security Administration. The Government is +// granted for itself and others acting on its behalf a nonexclusive, +// paid-up, irrevocable worldwide license in this material to reproduce, +// prepare derivative works, distribute copies to the public, perform +// publicly and display publicly, and to permit others to do so. +//------------------------------------------------------------------------------ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifndef CATCH_CONFIG_FAST_COMPILE +#define CATCH_CONFIG_FAST_COMPILE +#include +#endif + +#include +#include +#include + +using singularity::Dust; +using EOS = singularity::Variant; + +SCENARIO("Dust EOS", "[Dust]") { + GIVEN("A dust EOS") { + constexpr Real Cv = 1; + EOS dust = Dust(Cv); + THEN("The pressure is zero") { + REQUIRE(dust.PressureFromDensityInternalEnergy(1, 1) == 0); + } + } +} diff --git a/joss-paper/.gitignore b/joss-paper/.gitignore new file mode 100644 index 0000000000..865faf10cb --- /dev/null +++ b/joss-paper/.gitignore @@ -0,0 +1 @@ +auto diff --git a/joss-paper/paper.md b/joss-paper/paper.md new file mode 100644 index 0000000000..5f781a524e --- /dev/null +++ b/joss-paper/paper.md @@ -0,0 +1,276 @@ +--- +title: 'Singularity-EOS: Performance Portable Equations of State and Mixed Cell Closures' +tags: + - C++ + - Fortran + - Python + - equations of state + - thermodynamics + - performance portability +authors: + - name: Jonah M. Miller + orcid: 0000-0001-6432-7860 + affiliation: "1, 2" + corresponding: true + - name: Daniel A. Holladay + orcid: 0000-0002-0673-9741 + affiliation: "2, 3" + - name: Jeffrey H. Peterson + orcid: 0000-0001-9425-4674 + affiliation: 4 + - name: Christopher M. Mauney + orcid: 0000-0002-7827-2247 + affiliation: "2, 5" + - name: Richard Berger + orcid: 0000-0002-3044-8266 + affiliation: 3 + - name: Anna Pietarila Graham + affiliation: 5 + - name: Karen C. Tsai + orcid: 0000-0003-2848-832X + affiliation: 3 + - name: Brandon Barker + orcid: 0000-0002-8825-0893 + affiliation: "1, 2, 6, 7" + - name: Alexander Holas + orcid: 0000-0001-5184-6928 + affiliation: "2, 3, 8" + - name: Ann E. Mattsson + orcid: 0000-0002-0677-7537 + affiliation: 9 + - name: Mariam Gogilashvili + orcid: 0000-0002-6944-8052 + affiliation: "1, 2, 7, 10" + - name: Joshua C. Dolence + orcid: 0000-0003-4353-8751 + affiliation: "1, 2" + - name: Chad D. Meyer + orcid: 0000-0002-7530-6173 + affiliation: 11 + - name: Sriram Swaminarayan + orcid: 0000-0003-1809-5231 + affiliation: 3 + - name: Christoph Junghans + orcid: 0000-0003-0925-1458 + affiliation: 3 +affiliations: + - name: CCS-2, Computational Physics and Methods, Los Alamos National Laboratory, USA + index: 1 + - name: Center for Theoretical Astrophysics, Los Alamos National Laboratory, Los Alamos, NM + index: 2 + - name: CCS-7, Applied Computer Science, Los Alamos National Laboratory, USA + index: 3 + - name: XCP-2, Eulerian Codes, Los Alamos National Laboratory, USA + index: 4 + - name: HPC-ENV, HPC Environments, Los Alamos National Laboratory, USA + index: 5 + - name: Department of Physics and Astronomy, Michigan State University, USA + index: 6 + - name: Center for Nonlinear Studies, Los Alamos National Laboratory, USA + index: 7 + - name: Heidelberg Institute for Theoretical Studies, Germany + index: 8 + - name: XCP-5, Materials and Physical Data, Los Alamos National Laboratory, USA + index: 9 + - name: Department of Physics, Florida State University, USA + index: 10 + - name: XCP-4, Continuum Models and Numerical Methods, Los Alamos National Laboratory, USA + index: 11 +date: 13 April 2024 +bibliography: refs.bib + +--- + +# Summary + +We present Singularity-EOS, a new performance-portable library for +equations of state and related capabilities. Singularity-EOS provides +a large set of analytic equations of state, such as the Gruneisen +equation of state, and tabulated equation of state data under a +unified interface. It also provides support capabilities around these +equations of state, such as Python wrappers, solvers for finding +pressure-temperature equilibrium between multiple equations of state, +and a unique *modifier* framework, allowing the user to transform a +base equation of state, for example by shifting or scaling the +specific internal energy. All capabilities are performance portable, +meaning they compile and run on both CPU and GPU for a wide variety of +architectures. + +# Statement of need and State of the Field + +When expressed mathematically for continuous materials, the laws of +conservation of mass, energy, and momentum form the Navier-Stokes +equations of fluid dynamics. In the limit of zero molecular viscosity, +they become the Euler equations. These laws have been used to describe +phenomena as disparate as flow of air over an airplane wing, bacterial +motion in fluids, and the cataclysmic deaths of stars. However, the +fluid equations are not complete, and the system must be *closed* by a +description of the material at a sub-continuum (e.g., molecular or +atomic) scale. This closure is commonly called the *equation of state* +(EOS). + +Equations of state vary from the simple ideal gas law, to +sophisticated multi-phase descriptions of the lattice +structure of ice or wood, to models of quark-gluon plasma and nuclear +pasta at ultra high densities. A common form to write an equation of +state is as a pair of relations: + +$$P = P(\rho, T, \vec{\lambda}) \text{ and } \varepsilon = \varepsilon(\rho, T, \vec{\lambda}),$$ + +which relate the pressure $P$ and specific internal energy +$\varepsilon$ to density $\rho$, temperature $T$, and potentially some +unknown set of additional quantities $\vec{\lambda}$. However, other +representations are possible, and in common parlance an EOS is the +collection of knowledge needed to reconstruct some intrinsic +thermodynamic quantities from others. For example, the speed of sound +through a material or the specific heat capacity, which are +thermodynamic derivatives of the pressure and the specific internal +energy respectively, can both be determined by the EOS. + +In multi-material fluid dynamics simulations, one often will end up +with a so-called *mixed cell*, where two materials exist within +the same simulation zone. This can be an artifact of the numerical +representation; for example a steel bar and the surrounding air may +end up sharing a finite volume cell if the boundaries of the cell do +not align exactly with the surface of the steel bar, or, it may +represent physical reality; for example, air is a mixture of nitrogen +and oxygen gases, as well as water vapor. Regardless of the nature of +the mixed cell, one must somehow provide, to the fluid code, what the +material properties of the cell are as a whole. This is called a +*mixed cell closure.* One such closure is +*pressure-temperature equilibrium* (PTE), where all materials +in the cell are assumed to be at the same pressure and temperature. + +Typically fluid dynamics codes each develop an EOS package +individually to meet a given problem's needs. Databases of tabulated +equations of state, such as the Sesame [@sesame] and Stellar +Collapse [@stellarcollapseweb] databases often come with tabulated +data readers, for example, the EOSPAC library +[@PimentelDavidA2021EUMV] and Stellar Collapse library +[@stellarcollapsetables]. However, these libraries typically do +not include analytic equations of state or provide a unified API. They +also don't provide extra equation-of-state capabilities, such as +equilibrium solvers or production hardening. With a few exceptions, +these libraries are also typically not GPU-capable. + +We present Singularity-EOS, which aims to be a "one stop shop" for +EOS models for fluid and continuum dynamics codes. It provides a +unified interface for both analytic and tabulated equations of +state. It also provides useful surrounding capabilities, such as +Python wrappers, *modifiers*, which allow the user to transform a +given EOS, and solvers which can find the state in which multiple +EOS's are in PTE. To support usability, the library is extensively +documented and tested and supports builds through both ``cmake`` +and ``Spack`` [@spack]. + +Singularity-EOS leverages the ``Kokkos`` [@Kokkos] library for +performance portability, meaning the code can run on both CPUs and +GPUs, as well as other accelerators. This fills an important need, as +modern super computing capabilities increasingly rely on GPUs for +performance. Singularity-EOS is now used in the ongoing open-source +[Phoebus](https://github.com/lanl/phoebus) project which has a +separate code paper in-preparation. + +# Design Principles and Feature Highlights + +Here we enumerate several design principles underlying +Singularity-EOS, and highlight a few feature of the library. + +## Flexibility in loop patterns + +Singularity-EOS provides both scalar and vector APIs, allowing the +user to make EOS calls on both single points in thermodynamic space, +and on collections of points. The vector calls may be more performant +(as they may vectorize), however care is made to ensure both APIs +operate at acceptable performance, to accommodate different code +structures downstream. + +## Flexibility in memory layout + +The vector calls in Singularity-EOS use an *accessor* API and (with a +few exceptions) accept any C++ object that has a ``operator[]`` +function defined. This allows users to lay out their memory as they +see fit and use Singularity-EOS even on strided or sparsely allocated +memory. + +## Expose APIs to aid performance + +Many equations of state are most naturally represented as functions of +density and temperature. However, fluid codes require pressure as a +function of density and internal energy. Extracting this often +requires computing a root to invert the relation + +$$\varepsilon = \varepsilon(\rho, T).$$ + +In these cases, we expose an initial guess for temperature, which +helps the solution rapidly converge. Similarly, the performance of a +sequence of EOS calls may depend on the ordering of the calls. For +example, if both temperature and pressure are required from an +equation of state that requires inversion, requesting pressure first +will be less performant than requesting temperature first, as the +former requires two root finds, and the latter requires only one. To +enable this, we expose a function ``FillEos``, in which the user may +request multiple quantities at once, and the code uses ordering +knowledge to compute them as performantly as possible. + +## Performance-portable polymorphism + +Accelerators present new challenges to standard object-oriented +programming. In particular, not all compiler stacks (such as Sycl +[@SYCL] or OpenMP Target Offload [@chandra2001parallel]) +support relocatable device code, which is required for standard C++ +polymorphism. Even in programming models, such as CUDA [@cuda], +which do support relocatable device code, polymorphism can be slower +than naively expected, and the user-level API can be cumbersome, +requiring operations such as ``placement new``. To sidestep these +issues, we use the C++ language feature ``std::variant`` to +implement a polymorphism mechanism that works on device. + +## Modifiers + +A given code may need to modify an EOS model to make it suitable for a +given application. For example, the zero-point of the energy may need +to be shifted, a porosity model may need to be added, or the unit +system may need to be changed. We implement this with a system of +*modifiers*, which can be applied on top of an EOS in a generic +way. Modifiers may also be chained. + +## Fast log-lookups + +To span the required orders of magnitude, equations of state +are often tabulated on log-spaced grids. Logarithms and exponentials +are, however, expensive operations and the performance of lookups can +suffer. We instead use the not-quite-transcendental lookups described +in [@NQT] to significantly enhance performance of log-like lookups. + +## Extensibility via modular parts and plugins + +Singularity-EOS is designed to be extensible. The +``std::variant``-based polymorphism, combined with modifiers, as +described above, already provides significant flexibility. However, +downstream codes may wish to add functionality to the library. This +may be implemented in several ways. **First**, as Singularity-EOS is +open source, contributions from downstream developers are +welcome. **Second**, a C++ code that depends on Singularity-EOS may +implement their own models and include them in a local variant +object. Singularity-EOS provides tooling to build variants up +iteratively. **Finally**, Singularity-EOS provides a flexible plugin +infrastructure that allows downstream users to add capability to the +core library locally by telling the build system to include a locally +downloaded plugin. This final capability allows downstream users to +share code with each other, even when committing that code to +Singularity-EOS proper is not possible due to, e.g., licensing issues. + +# Acknowledgements + +This work was supported through the Laboratory Directed Research and +Development program, the Center for Space and Earth Sciences, and the +Center for Nonlinear Studies under project numbers 20240477CR-SES and +20220564ECR at Los Alamos National Laboratory (LANL). LANL is operated +by Triad National Security, LLC, for the National Nuclear Security +Administration of U.S. Department of Energy (Contract +No. 89233218CNA000001). This research used resources provided by the +Darwin testbed at LANL which is funded by the Computational Systems +and Software Environments subprogram of LANL's Advanced Simulation and +Computing program (NNSA/DOE). This work is approved for unlimited +release with report number LA-UR-24-23364. diff --git a/joss-paper/refs.bib b/joss-paper/refs.bib new file mode 100644 index 0000000000..3c4086b8a6 --- /dev/null +++ b/joss-paper/refs.bib @@ -0,0 +1,177 @@ +@ARTICLE{fornax, + author = {{Skinner}, M. Aaron and {Dolence}, Joshua C. and {Burrows}, Adam and {Radice}, David and {Vartanyan}, David}, + title = "{FORNAX: A Flexible Code for Multiphysics Astrophysical Simulations}", + journal = {\apjs}, + keywords = {methods: numerical, Astrophysics - Instrumentation and Methods for Astrophysics, Astrophysics - High Energy Astrophysical Phenomena, Astrophysics - Solar and Stellar Astrophysics, Physics - Computational Physics}, + year = 2019, + month = mar, + volume = {241}, + number = {1}, + eid = {7}, + pages = {7}, + doi = {10.3847/1538-4365/ab007f}, +archivePrefix = {arXiv}, + eprint = {1806.07390}, + primaryClass = {astro-ph.IM}, + adsurl = {https://ui.adsabs.harvard.edu/abs/2019ApJS..241....7S}, + adsnote = {Provided by the SAO/NASA Astrophysics Data System} +} + +@ARTICLE{nubhlight, + author = {{Miller}, Jonah M. and {Ryan}, Ben. R. and {Dolence}, Joshua C.}, + title = "{{\ensuremath{\nu}} bhlight: Radiation GRMHD for Neutrino-driven Accretion Flows}", + journal = {\apjs}, + keywords = {accretion, accretion disks, black hole physics, magnetohydrodynamics: MHD, methods: numerical, neutrinos, radiative transfer, Astrophysics - Instrumentation and Methods for Astrophysics, General Relativity and Quantum Cosmology, Physics - Computational Physics}, + year = 2019, + month = apr, + volume = {241}, + number = {2}, + eid = {30}, + pages = {30}, + doi = {10.3847/1538-4365/ab09fc}, +archivePrefix = {arXiv}, + eprint = {1903.09273}, + primaryClass = {astro-ph.IM}, + adsurl = {https://ui.adsabs.harvard.edu/abs/2019ApJS..241...30M}, + adsnote = {Provided by the SAO/NASA Astrophysics Data System} +} + +@techreport{sesame, +author = "Lyon, Stanford P. and Johnson, James D.", +title = "Sesame: The Los Alamos National Laboratory Equation of State Database", +institution = "Los Alamos National Laboratory", +number="LA-UR-92-3407", +year = "1992"} + +@article{stellarcollapsetables, + author={Evan O'Connor and Christian D Ott}, + title={A new open-source code for spherically symmetric stellar collapse to neutron stars and black holes}, + journal={Classical and Quantum Gravity}, + volume={27}, + number={11}, + pages={114103}, + url={http://stacks.iop.org/0264-9381/27/i=11/a=114103}, + year={2010}, +} + +@Misc{stellarcollapseweb, + author = {Evan O'Connor and Christian D Ott}, + title = {Stellar Collapse: Microphysics}, + year = {2010}, + url = {https://stellarcollapse.org/equationofstate}, + note = {Online access. \url{https://stellarcollapse.org/equationofstate}}, +} + +@book{PimentelDavidA2021EUMV, +year = {2021}, +title = {EOSPAC User’s Manual: V.6.5}, +language = {eng}, +address = {United States}, +author = {Pimentel, David A}, +keywords = {EOSPAC SESAME Equation of State Interpolation Thermodynamics ; MATHEMATICS AND COMPUTING}, +organization = {Los Alamos National Lab. (LANL), Los Alamos, NM (United States)}, +} + +@ARTICLE{SullivanWeak, + author = {{Sullivan}, Chris and {O'Connor}, Evan and {Zegers}, Remco G.~T. and {Grubb}, Thomas and {Austin}, Sam M.}, + title = "{The Sensitivity of Core-collapse Supernovae to Nuclear Electron Capture}", + journal = {\apj}, + keywords = {neutrinos, nuclear reactions, nucleosynthesis, abundances, equation of state, supernovae: general, Astrophysics - High Energy Astrophysical Phenomena, Nuclear Experiment, Nuclear Theory}, + year = 2016, + month = jan, + volume = {816}, + number = {1}, + eid = {44}, + pages = {44}, + doi = {10.3847/0004-637X/816/1/44}, +archivePrefix = {arXiv}, + eprint = {1508.07348}, + primaryClass = {astro-ph.HE}, + adsurl = {https://ui.adsabs.harvard.edu/abs/2016ApJ...816...44S}, + adsnote = {Provided by the SAO/NASA Astrophysics Data System} +} + +@book{press2007numerical, + title={Numerical Recipes with Source Code CD-ROM 3rd Edition: The Art of Scientific Computing}, + author={Press, W.H. and Teukolsky, S.A. and Vetterling, W.T. and Flannery, B.P.}, + isbn={9780521884075}, + lccn={2007062003}, + series={Numerical Recipes: The Art of Scientific Computing}, + url={https://books.google.com/books?id=DyykEZo4fwUC}, + year={2007}, + publisher={Cambridge University Press} +} + +@ARTICLE{Kokkos, + author={Trott, Christian R. and Lebrun-Grandié, Damien and Arndt, Daniel and Ciesko, Jan and Dang, Vinh and Ellingwood, Nathan and Gayatri, Rahulkumar and Harvey, Evan and Hollman, Daisy S. and Ibanez, Dan and Liber, Nevin and Madsen, Jonathan and Miles, Jeff and Poliakoff, David and Powell, Amy and Rajamanickam, Sivasankaran and Simberg, Mikael and Sunderland, Dan and Turcksin, Bruno and Wilke, Jeremiah}, + journal={IEEE Transactions on Parallel and Distributed Systems}, + title={Kokkos 3: Programming Model Extensions for the Exascale Era}, + year={2022}, + volume={33}, + number={4}, + pages={805-817}, + doi={10.1109/TPDS.2021.3097283}} + + @misc{cuda, + author={NVIDIA and Vingelmann, Péter and Fitzek, Frank H.P.}, + title={CUDA, release: 10.2.89}, + year={2020}, + url={https://developer.nvidia.com/cuda-toolkit}, +} + + @book{chandra2001parallel, + title={Parallel programming in OpenMP}, + author={Chandra, Rohit and Dagum, Leo and Kohr, David and Menon, Ramesh and Maydan, Dror and McDonald, Jeff}, + year={2001}, + publisher={Morgan kaufmann} +} + +@inproceedings{SYCL, +author = {Reyes, Ruyman and Brown, Gordon and Burns, Rod and Wong, Michael}, +title = {SYCL 2020: More than Meets the Eye}, +year = {2020}, +isbn = {9781450375313}, +publisher = {Association for Computing Machinery}, +address = {New York, NY, USA}, +url = {https://doi.org/10.1145/3388333.3388649}, +doi = {10.1145/3388333.3388649}, +booktitle = {Proceedings of the International Workshop on OpenCL}, +articleno = {4}, +numpages = {1}, +keywords = {HPC, SYCL, CUDA, OpenCL}, +location = {Munich, Germany}, +series = {IWOCL '20} +} + +@ARTICLE{NQT, + author = {{Miller}, Jonah M. and {Dolence}, Joshua C. and {Holladay}, Daniel}, + title = "{Not-Quite Transcendental Functions and their Applications}", + journal = {arXiv e-prints}, + keywords = {Physics - Computational Physics, Computer Science - Performance, Mathematics - Numerical Analysis}, + year = 2022, + month = jun, + eid = {arXiv:2206.08957}, + pages = {arXiv:2206.08957}, + doi = {10.48550/arXiv.2206.08957}, +archivePrefix = {arXiv}, + eprint = {2206.08957}, + primaryClass = {physics.comp-ph}, + adsurl = {https://ui.adsabs.harvard.edu/abs/2022arXiv220608957M}, + adsnote = {Provided by the SAO/NASA Astrophysics Data System} +} + +@inproceedings{spack, +author = {Gamblin, Todd and LeGendre, Matthew and Collette, Michael R. and Lee, Gregory L. and Moody, Adam and de Supinski, Bronis R. and Futral, Scott}, +title = {The Spack Package Manager: Bringing Order to HPC Software Chaos}, +year = {2015}, +isbn = {9781450337236}, +publisher = {Association for Computing Machinery}, +address = {New York, NY, USA}, +url = {https://doi.org/10.1145/2807591.2807623}, +doi = {10.1145/2807591.2807623}, +booktitle = {Proceedings of the International Conference for High Performance Computing, Networking, Storage and Analysis}, +articleno = {40}, +numpages = {12}, +location = {Austin, Texas}, +series = {SC '15} +} diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index e2f0a4e3cc..6111edb399 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -23,7 +23,7 @@ pybind11_add_module(singularity_eos modifier_relativistic.cpp modifier_bilinear_ramp.cpp ) -target_link_libraries(singularity_eos PRIVATE singularity-eos) +target_link_libraries(singularity_eos PRIVATE singularity-eos_Interface) include(GNUInstallDirs) diff --git a/python/module.cpp b/python/module.cpp index 81db516a72..2b89795552 100644 --- a/python/module.cpp +++ b/python/module.cpp @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// © 2021-2023. Triad National Security, LLC. All rights reserved. This +// © 2021-2024. Triad National Security, LLC. All rights reserved. This // program was produced under U.S. Government contract 89233218CNA000001 // for Los Alamos National Laboratory (LANL), which is operated by Triad // National Security, LLC for the U.S. Department of Energy/National @@ -60,9 +60,9 @@ PYBIND11_MODULE(singularity_eos, m) { eos_class(m, "DavisProducts") .def(py::init()) .def( - py::init(), + py::init(), py::arg("a"), py::arg("b"), py::arg("k"), py::arg("n"), py::arg("vc"), - py::arg("pc"), py::arg("Cv"), py::arg("E0") + py::arg("pc"), py::arg("Cv") ); #ifdef SPINER_USE_HDF @@ -141,6 +141,7 @@ PYBIND11_MODULE(singularity_eos, m) { thermalqs.attr("temperature") = pybind11::int_(thermalqs::temperature); thermalqs.attr("specific_heat") = pybind11::int_(thermalqs::specific_heat); thermalqs.attr("bulk_modulus") = pybind11::int_(thermalqs::bulk_modulus); + thermalqs.attr("do_lambda") = pybind11::int_(thermalqs::do_lambda); thermalqs.attr("all_values") = pybind11::int_(thermalqs::all_values); py::module eos_units = m.def_submodule("eos_units"); diff --git a/python/module.hpp b/python/module.hpp index a4a3788a8f..dd22dc6cb2 100644 --- a/python/module.hpp +++ b/python/module.hpp @@ -14,6 +14,7 @@ // clang-format off #include #include +#include #include #include #include @@ -24,17 +25,18 @@ namespace py = pybind11; using namespace singularity; +using singularity::variadic_utils::np; // Helper function to convert lambda numpy array to double* buffer // With std::optional we would add support for a default value of lambda=None -template +template Real two_params(const T& self, const Real a, const Real b, py::array_t lambda) { return (self.*Func)(a, b, lambda.mutable_data()); } -template +template Real two_params_no_lambda(const T& self, const Real a, const Real b) { - return (self.*Func)(a, b, nullptr); + return (self.*Func)(a, b, np()); } class LambdaHelper { @@ -326,7 +328,7 @@ py::class_ eos_class(py::module_ & m, std::string name) { auto lambda = kwargs["lmbda"].cast>(); self.FillEos(s.density, s.temperature, s.specific_internal_energy, s.pressure, s.specific_heat, s.bulk_modulus, output, lambda.mutable_data()); } else { - self.FillEos(s.density, s.temperature, s.specific_internal_energy, s.pressure, s.specific_heat, s.bulk_modulus, output, nullptr); + self.FillEos(s.density, s.temperature, s.specific_internal_energy, s.pressure, s.specific_heat, s.bulk_modulus, output, np()); } return s; }) @@ -337,7 +339,7 @@ py::class_ eos_class(py::module_ & m, std::string name) { }) .def("ValuesAtReferenceState", [](const T & self){ EOSState s; - self.ValuesAtReferenceState(s.density, s.temperature, s.specific_internal_energy, s.pressure, s.specific_heat, s.bulk_modulus, s.dpde, s.dvdt, nullptr); + self.ValuesAtReferenceState(s.density, s.temperature, s.specific_internal_energy, s.pressure, s.specific_heat, s.bulk_modulus, s.dpde, s.dvdt, np()); return s; }) @@ -354,7 +356,7 @@ py::class_ eos_class(py::module_ & m, std::string name) { }, py::arg("press"), py::arg("temp"), py::arg("lmbda")) .def("DensityEnergyFromPressureTemperature", [](const T & self, const Real press, const Real temp) { Real rho, sie; - self.DensityEnergyFromPressureTemperature(press, temp, nullptr, rho, sie); + self.DensityEnergyFromPressureTemperature(press, temp, np(), rho, sie); return std::pair(rho, sie); }, py::arg("press"), py::arg("temp")) .def("Finalize", &T::Finalize) diff --git a/sesame2spiner/examples/unit_tests/copper.dat b/sesame2spiner/examples/unit_tests/copper.dat new file mode 100644 index 0000000000..16ba63d428 --- /dev/null +++ b/sesame2spiner/examples/unit_tests/copper.dat @@ -0,0 +1,20 @@ +# ====================================================================== +# Example input deck for sesame2spiner, +# a tool for converting eospac to spiner +# Author: Jonah Miller (jonahm@lanl.gov) +# © 2021-2024. Triad National Security, LLC. All rights reserved. This +# program was produced under U.S. Government contract 89233218CNA000001 +# for Los Alamos National Laboratory (LANL), which is operated by Triad +# National Security, LLC for the U.S. Department of Energy/National +# Nuclear Security Administration. All rights in the program are +# reserved by Triad National Security, LLC, and the U.S. Department of +# Energy/National Nuclear Security Administration. The Government is +# granted for itself and others acting on its behalf a nonexclusive, +# paid-up, irrevocable worldwide license in this material to reproduce, +# prepare derivative works, distribute copies to the public, perform +# publicly and display publicly, and to permit others to do so. +# ====================================================================== + +matid=3337 +name=copper +rhomin=0. diff --git a/singularity-eos/CMakeLists.txt b/singularity-eos/CMakeLists.txt index 46c86316a7..399702f989 100644 --- a/singularity-eos/CMakeLists.txt +++ b/singularity-eos/CMakeLists.txt @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------# -# © 2021-2023. Triad National Security, LLC. All rights reserved. This +# © 2021-2024. Triad National Security, LLC. All rights reserved. This # program was produced under U.S. Government contract 89233218CNA000001 # for Los Alamos National Laboratory (LANL), which is operated by Triad # National Security, LLC for the U.S. Department of Energy/National @@ -12,7 +12,18 @@ # publicly and display publicly, and to permit others to do so. #------------------------------------------------------------------------------# -set(EOS_HEADERS +# Special sauce so generated file has proper include path +configure_file(eos/eos.hpp.in + ${CMAKE_BINARY_DIR}/generated/singularity-eos/eos/eos.hpp + @ONLY) + +register_headers( + # tell cmake: + # (1) that if this file is changed, we gotta rebuild + # (2) to copy this file into the install for posterity + eos/eos.hpp.in + + # Normal files base/fast-math/logs.hpp base/robust_utils.hpp base/root-finding-1d/root_finding.hpp @@ -20,12 +31,16 @@ set(EOS_HEADERS base/math_utils.hpp base/constants.hpp base/eos_error.hpp + base/error_utils.hpp base/sp5/singularity_eos_sp5.hpp - eos/eos.hpp + eos/default_variant.hpp + base/hermite.hpp eos/eos_variant.hpp - eos/singularity_eos.hpp eos/eos_stellar_collapse.hpp eos/eos_ideal.hpp + eos/eos_models.hpp + eos/eos_mgusup.hpp + eos/eos_powermg.hpp eos/eos_spiner.hpp eos/eos_davis.hpp eos/eos_gruneisen.hpp @@ -34,6 +49,7 @@ set(EOS_HEADERS eos/eos_jwl.hpp eos/eos_helmholtz.hpp eos/eos_sap_polynomial.hpp + eos/eos_type_lists.hpp eos/modifiers/relativistic_eos.hpp eos/modifiers/scaled_eos.hpp eos/modifiers/ramps_eos.hpp @@ -43,35 +59,36 @@ set(EOS_HEADERS eos/eos_eospac.hpp eos/eos_noble_abel.hpp eos/eos_stiff.hpp + eos/singularity_eos_init_utils.hpp + eos/variant_utils.hpp + eos/eos_carnahan_starling.hpp ) -set(EOS_SRCS eos/eos.cpp) - if (SINGULARITY_BUILD_CLOSURE) - list(APPEND EOS_HEADERS - closure/mixed_cell_models.hpp) + register_headers(closure/mixed_cell_models.hpp) + if (SINGULARITY_USE_FORTRAN OR SINGULARITY_BUILD_TESTS) + # while these are C++ files, they + # are only needed for the fortran backend or unit testing + register_srcs(eos/singularity_eos.cpp) + register_headers(eos/singularity_eos.hpp) + endif() if (SINGULARITY_USE_FORTRAN) - list(APPEND EOS_SRCS - eos/get_sg_eos.cpp) + register_srcs(eos/get_sg_eos.cpp) if (SINGULARITY_USE_KOKKOS) - list(APPEND EOS_SRCS + register_srcs( eos/get_sg_eos_p_t.cpp eos/get_sg_eos_rho_t.cpp eos/get_sg_eos_rho_p.cpp eos/get_sg_eos_rho_e.cpp) endif() - list(APPEND EOS_HEADERS + register_headers( eos/get_sg_eos.hpp eos/get_sg_eos_functors.hpp) endif() endif() if (SINGULARITY_USE_FORTRAN) - list(APPEND EOS_SRCS eos/singularity_eos.f90) - list(APPEND EOS_SRCS eos/singularity_eos.cpp) - list(APPEND EOS_HEADERS eos/singularity_eos.hpp) + register_srcs( + eos/singularity_eos.f90 + ) endif() - -# export to parent scope -set(EOS_HEADERS ${EOS_HEADERS} PARENT_SCOPE) -set(EOS_SRCS ${EOS_SRCS} PARENT_SCOPE) diff --git a/singularity-eos/base/constants.hpp b/singularity-eos/base/constants.hpp index bdbf21ca6d..303361534a 100644 --- a/singularity-eos/base/constants.hpp +++ b/singularity-eos/base/constants.hpp @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// © 2021-2023. Triad National Security, LLC. All rights reserved. This +// © 2021-2024. Triad National Security, LLC. All rights reserved. This // program was produced under U.S. Government contract 89233218CNA000001 // for Los Alamos National Laboratory (LANL), which is operated by Triad // National Security, LLC for the U.S. Department of Energy/National @@ -27,7 +27,8 @@ constexpr unsigned long pressure = (1 << 2); constexpr unsigned long temperature = (1 << 3); constexpr unsigned long specific_heat = (1 << 4); constexpr unsigned long bulk_modulus = (1 << 5); -constexpr unsigned long all_values = (1 << 6) - 1; +constexpr unsigned long do_lambda = (1 << 6); +constexpr unsigned long all_values = (1 << 7) - 1; } // namespace thermalqs constexpr size_t MAX_NUM_LAMBDAS = 3; diff --git a/singularity-eos/base/error_utils.hpp b/singularity-eos/base/error_utils.hpp new file mode 100644 index 0000000000..e8cbbae31b --- /dev/null +++ b/singularity-eos/base/error_utils.hpp @@ -0,0 +1,88 @@ +//------------------------------------------------------------------------------ +// © 2021-2024. Triad National Security, LLC. All rights reserved. This +// program was produced under U.S. Government contract 89233218CNA000001 +// for Los Alamos National Laboratory (LANL), which is operated by Triad +// National Security, LLC for the U.S. Department of Energy/National +// Nuclear Security Administration. All rights in the program are +// reserved by Triad National Security, LLC, and the U.S. Department of +// Energy/National Nuclear Security Administration. The Government is +// granted for itself and others acting on its behalf a nonexclusive, +// paid-up, irrevocable worldwide license in this material to reproduce, +// prepare derivative works, distribute copies to the public, perform +// publicly and display publicly, and to permit others to do so. +//------------------------------------------------------------------------------ + +#ifndef SINGULARITY_EOS_BASE_ERROR_UTILS_HPP_ +#define SINGULARITY_EOS_BASE_ERROR_UTILS_HPP_ + +#include +#include + +#include + +namespace singularity { +namespace error_utils { + +using PortsOfCall::printf; + +constexpr double _NORMAL_FACTOR = 1.0e10; + +struct is_normal_or_zero { + template + bool PORTABLE_FORCEINLINE_FUNCTION operator()(valT value) const { + static_assert(std::is_floating_point::value); + return (value == valT{0}) || + (std::isnormal(_NORMAL_FACTOR * value) && std::isnormal(value)); + } +}; + +struct is_strictly_positive { + template + bool PORTABLE_FORCEINLINE_FUNCTION operator()(valT value) const { + static_assert(std::is_arithmetic::value); + return value > valT{0}; + } +}; + +struct is_non_negative { + template + bool PORTABLE_FORCEINLINE_FUNCTION operator()(valT value) const { + static_assert(std::is_arithmetic::value); + return value >= valT{0}; + } +}; + +// Checks whether a value obeys some sort of provided condition. If not, returns true and +// prints the provided error message, variable name, and value (but does not abort!) +template +PORTABLE_FORCEINLINE_FUNCTION bool violates_condition(valT &&value, condT &&condition, + nameT &&var_name) { + const bool good = condition(std::forward(value)); + if (!good) { + printf("### ERROR: Bad singularity-eos value\n Var: %s\n Value: %.15e\n", + var_name, value); + } + return !good; +} + +// Create specialized functions using the above conditions +template +PORTABLE_FORCEINLINE_FUNCTION bool bad_value(valT &&value, nameT &&var_name) { + return violates_condition(std::forward(value), is_normal_or_zero{}, + std::forward(var_name)); +} +template +PORTABLE_FORCEINLINE_FUNCTION bool non_positive_value(valT &&value, nameT &&var_name) { + return violates_condition(std::forward(value), is_strictly_positive{}, + std::forward(var_name)); +} +template +PORTABLE_FORCEINLINE_FUNCTION bool negative_value(valT &&value, nameT &&var_name) { + return violates_condition(std::forward(value), is_strictly_positive{}, + std::forward(var_name)); +} + +} // namespace error_utils +} // namespace singularity + +#endif // #ifndef SINGULARITY_EOS_BASE_ERROR_UTILS_HPP_ diff --git a/singularity-eos/base/variadic_utils.hpp b/singularity-eos/base/variadic_utils.hpp index 50e9b14269..e0ef3d95dc 100644 --- a/singularity-eos/base/variadic_utils.hpp +++ b/singularity-eos/base/variadic_utils.hpp @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// © 2021-2023. Triad National Security, LLC. All rights reserved. This +// © 2021-2024. Triad National Security, LLC. All rights reserved. This // program was produced under U.S. Government contract 89233218CNA000001 // for Los Alamos National Laboratory (LANL), which is operated by Triad // National Security, LLC for the U.S. Department of Energy/National @@ -16,6 +16,7 @@ #define SINGULARITY_EOS_BASE_VARIADIC_UTILS_HPP_ #include +#include namespace singularity { namespace variadic_utils { @@ -23,6 +24,35 @@ namespace variadic_utils { // Some generic variatic utilities // ====================================================================== +// Useful for generating nullptr of a specific pointer type +template +inline constexpr T *np() { + return nullptr; +} + +// C++14 implementation of std::remove_cvref (available since C++20) +// credit to CJ + Diego +template +struct remove_cvref { + typedef std::remove_cv_t> type; +}; + +// Helper types +template +using remove_cvref_t = typename remove_cvref::type; + +// SFINAE to check if a value is a null ptr +template >::value>::type> +constexpr inline bool is_nullptr(T &&t) { + return std::forward(t) == nullptr; +} +template >::value>::type * = nullptr> +constexpr inline bool is_nullptr(T &&) { + return false; +} + // Backport of C++17 bool_constant. // With C++17, can be replaced with // using std::bool_constant diff --git a/singularity-eos/closure/mixed_cell_models.hpp b/singularity-eos/closure/mixed_cell_models.hpp index 365e1dd4a6..f8c0335e38 100644 --- a/singularity-eos/closure/mixed_cell_models.hpp +++ b/singularity-eos/closure/mixed_cell_models.hpp @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// © 2021-2023. Triad National Security, LLC. All rights reserved. This +// © 2021-2024. Triad National Security, LLC. All rights reserved. This // program was produced under U.S. Government contract 89233218CNA000001 // for Los Alamos National Laboratory (LANL), which is operated by Triad // National Security, LLC for the U.S. Department of Energy/National @@ -16,7 +16,9 @@ #define _SINGULARITY_EOS_CLOSURE_MIXED_CELL_MODELS_ #include +#include #include +#include #include #include @@ -52,6 +54,9 @@ constexpr Real line_search_fac = 0.5; constexpr Real vfrac_safety_fac = 0.95; constexpr Real minimum_temperature = 1.e-9; constexpr Real maximum_temperature = 1.e9; +constexpr Real temperature_limit = 1.0e15; +constexpr Real default_tguess = 300.; +constexpr Real min_dtde = 1.0e-16; } // namespace mix_params namespace mix_impl { @@ -165,10 +170,11 @@ class PTESolverBase { PORTABLE_INLINE_FUNCTION virtual void Fixup() const { Real vsum = 0; - for (int m = 0; m < nmat; ++m) + for (int m = 0; m < nmat; ++m) { vsum += vfrac[m]; + } for (int m = 0; m < nmat; ++m) - vfrac[m] *= vfrac_total / vsum; + vfrac[m] *= robust::ratio(vfrac_total, vsum); } // Finalize restores the temperatures, energies, and pressures to unscaled values from // the internally scaled quantities used by the solvers @@ -212,6 +218,9 @@ class PTESolverBase { // material m averaged over the full PTE volume rho_total = 0.0; for (int m = 0; m < nmat; ++m) { + PORTABLE_REQUIRE(vfrac[m] > 0., + "Non-positive volume fraction provided to PTE solver"); + PORTABLE_REQUIRE(rho[m] > 0., "Non-positive density provided to PTE solver"); rhobar[m] = rho[m] * vfrac[m]; rho_total += rhobar[m]; } @@ -223,13 +232,13 @@ class PTESolverBase { // set volume fractions for (int m = 0; m < nmat; ++m) { const Real rho_min = eos[m].RhoPmin(T); - const Real vmax = std::min(0.9 * rhobar[m] / rho_min, 1.0); + const Real vmax = std::min(0.9 * robust::ratio(rhobar[m], rho_min), 1.0); vfrac[m] = (vfrac[m] > 0.0 ? std::min(vmax, vfrac[m]) : vmax); vsum += vfrac[m]; } // Normalize vfrac for (int m = 0; m < nmat; ++m) { - vfrac[m] *= vfrac_total / vsum; + vfrac[m] *= robust::ratio(vfrac_total, vsum); } } @@ -241,12 +250,14 @@ class PTESolverBase { if (Tnorm > 0.0) { Tguess = Tnorm; } else { - Tguess = 300.0; + Tguess = mix_params::default_tguess; for (int m = 0; m < nmat; ++m) Tguess = std::max(Tguess, temp[m]); } + PORTABLE_REQUIRE(Tguess > 0., "Non-positive temperature guess for PTE"); // check for sanity. basically checks that the input temperatures weren't garbage - assert(Tguess < 1.0e15); + PORTABLE_REQUIRE(Tguess < mix_params::temperature_limit, + "Very large input temperature or temperature guess"); // iteratively increase temperature guess until all rho's are above rho_at_pmin const Real Tfactor = 10.0; bool rho_fail; @@ -256,7 +267,7 @@ class PTESolverBase { rho_fail = false; for (int m = 0; m < nmat; ++m) { const Real rho_min = eos[m].RhoPmin(Tguess); - rho[m] = rhobar[m] / vfrac[m]; + rho[m] = robust::ratio(rhobar[m], vfrac[m]); if (rho[m] < rho_min) { rho_fail = true; Tguess *= Tfactor; @@ -299,7 +310,7 @@ class PTESolverBase { // intialize rhobar array and final density InitRhoBarandRho(); - uscale = rho_total * sie_total; + uscale = rho_total * abs(sie_total); // guess some non-zero temperature to start const Real Tguess = GetTguess(); @@ -311,14 +322,14 @@ class PTESolverBase { temp[m] = 1.0; sie[m] = eos[m].InternalEnergyFromDensityTemperature(rho[m], Tguess, Cache[m]); // note the scaling of pressure - press[m] = this->GetPressureFromPreferred(eos[m], rho[m], Tguess, sie[m], Cache[m], - false) / - uscale; + press[m] = robust::ratio( + this->GetPressureFromPreferred(eos[m], rho[m], Tguess, sie[m], Cache[m], false), + uscale); } // note the scaling of the material internal energy densities for (int m = 0; m < nmat; ++m) - u[m] = sie[m] * rhobar[m] / uscale; + u[m] = sie[m] * robust::ratio(rhobar[m], uscale); } PORTABLE_INLINE_FUNCTION @@ -339,13 +350,13 @@ class PTESolverBase { Real rhoBsum = 0.0; Real Asum = 0.0; for (int m = 0; m < nmat; m++) { - Asum += vfrac[m] * press[m] / temp[m]; - rhoBsum += rho[m] * vfrac[m] * sie[m] / temp[m]; + Asum += vfrac[m] * robust::ratio(press[m], temp[m]); + rhoBsum += rho[m] * vfrac[m] * robust::ratio(sie[m], temp[m]); } Asum *= uscale / Tnorm; rhoBsum /= Tnorm; Tideal = uscale / rhoBsum / Tnorm; - Pideal = Tnorm * Tideal * Asum / vfrac_total / uscale; + Pideal = robust::ratio(Tnorm * Tideal * Asum, uscale * vfrac_total); } // Compute the ideal EOS PTE solution and replace the initial guess if it has a lower @@ -374,10 +385,11 @@ class PTESolverBase { res_norm_old += res[m] * res[m]; } // check if the volume fractions are reasonable - const Real alpha = Pideal / Tideal; + const Real alpha = robust::ratio(Pideal, Tideal); for (int m = 0; m < nmat; ++m) { - vfrac[m] *= press[m] / (temp[m] * alpha); - if (rhobar[m] / vfrac[m] < eos[m].RhoPmin(Tnorm * Tideal)) { + vfrac[m] *= robust::ratio(press[m], (temp[m] * alpha)); + if (Tnorm * Tideal < 0 || + robust::ratio(rhobar[m], vfrac[m]) < eos[m].RhoPmin(Tnorm * Tideal)) { // abort because this is putting this material into a bad state for (int n = m; n >= 0; n--) vfrac[n] = vtemp[n]; @@ -386,13 +398,15 @@ class PTESolverBase { } // fill in the rest of the state for (int m = 0; m < nmat; ++m) { - rho[m] = rhobar[m] / vfrac[m]; + rho[m] = robust::ratio(rhobar[m], vfrac[m]); + const Real sie_m = eos[m].InternalEnergyFromDensityTemperature(rho[m], Tnorm * Tideal, Cache[m]); - u[m] = rhobar[m] * sie_m / uscale; - press[m] = this->GetPressureFromPreferred(eos[m], rho[m], Tnorm * Tideal, sie_m, - Cache[m], false) / - uscale; + u[m] = rhobar[m] * robust::ratio(sie_m, uscale); + press[m] = + robust::ratio(this->GetPressureFromPreferred(eos[m], rho[m], Tnorm * Tideal, + sie_m, Cache[m], false), + uscale); } // fill in the residual solver->Residual(); @@ -415,7 +429,7 @@ class PTESolverBase { // did work, fill in temp and energy density for (int m = 0; m < nmat; ++m) { temp[m] = Tideal; - sie[m] = uscale * u[m] / rhobar[m]; + sie[m] = uscale * robust::ratio(u[m], rhobar[m]); } } } @@ -493,7 +507,7 @@ PORTABLE_INLINE_FUNCTION Real ApproxTemperatureFromRhoMatU( iter++; } - const Real alpha = (u_tot - ulo) / (uhi - ulo); + const Real alpha = robust::ratio((u_tot - ulo), (uhi - ulo)); return FastMath::pow2((1.0 - alpha) * lTlo + alpha * lThi); } @@ -551,7 +565,7 @@ class PTESolverRhoT : public mix_impl::PTESolverBase { vtemp = AssignIncrement(scratch, nmat); // TODO(JCD): use whatever lambdas are passed in /*for (int m = 0; m < nmat; m++) { - if (lambda[m] != nullptr) Cache[m] = lambda[m]; + if (!variadic_utils::is_nullptr(lambda[m])) Cache[m] = lambda[m]; }*/ } @@ -611,27 +625,29 @@ class PTESolverRhoT : public mix_impl::PTESolverBase { ////////////////////////////// Real dv = (vfrac[m] < 0.5 ? 1.0 : -1.0) * vfrac[m] * derivative_eps; const Real vf_pert = vfrac[m] + dv; - const Real rho_pert = rhobar[m] / vf_pert; + const Real rho_pert = robust::ratio(rhobar[m], vf_pert); Real p_pert{}; Real e_pert = eos[m].InternalEnergyFromDensityTemperature(rho_pert, Tnorm * Tequil, Cache[m]); - p_pert = this->GetPressureFromPreferred(eos[m], rho_pert, Tnorm * Tequil, e_pert, - Cache[m], false) / - uscale; - dpdv[m] = (p_pert - press[m]) / dv; - dedv[m] = (rhobar[m] * e_pert / uscale - u[m]) / dv; + p_pert = + robust::ratio(this->GetPressureFromPreferred(eos[m], rho_pert, Tnorm * Tequil, + e_pert, Cache[m], false), + uscale); + dpdv[m] = robust::ratio((p_pert - press[m]), dv); + dedv[m] = robust::ratio(rhobar[m] * robust::ratio(e_pert, uscale) - u[m], dv); ////////////////////////////// // perturb temperature ////////////////////////////// Real dT = Tequil * derivative_eps; e_pert = eos[m].InternalEnergyFromDensityTemperature(rho[m], Tnorm * (Tequil + dT), Cache[m]); - p_pert = this->GetPressureFromPreferred(eos[m], rho[m], Tnorm * (Tequil + dT), - e_pert, Cache[m], false) / - uscale; - dpdT[m] = (p_pert - press[m]) / dT; - dedT_sum += (rhobar[m] * e_pert / uscale - u[m]) / dT; + p_pert = robust::ratio(this->GetPressureFromPreferred(eos[m], rho[m], + Tnorm * (Tequil + dT), e_pert, + Cache[m], false), + uscale); + dpdT[m] = robust::ratio((p_pert - press[m]), dT); + dedT_sum += robust::ratio(rhobar[m] * robust::ratio(e_pert, uscale) - u[m], dT); } // Fill in the Jacobian @@ -653,11 +669,12 @@ class PTESolverRhoT : public mix_impl::PTESolverBase { PORTABLE_INLINE_FUNCTION Real ScaleDx() const { using namespace mix_params; + // Each check reduces the scale further if necessary Real scale = 1.0; // control how big of a step toward vfrac = 0 is allowed for (int m = 0; m < nmat; ++m) { if (scale * dx[m] < -vfrac_safety_fac * vfrac[m]) { - scale = -vfrac_safety_fac * vfrac[m] / dx[m]; + scale = -vfrac_safety_fac * robust::ratio(vfrac[m], dx[m]); } } const Real Tnew = Tequil + scale * dx[nmat]; @@ -665,14 +682,21 @@ class PTESolverRhoT : public mix_impl::PTESolverBase { for (int m = 0; m < nmat; m++) { const Real rho_min = std::max(eos[m].RhoPmin(Tnorm * Tequil), eos[m].RhoPmin(Tnorm * Tnew)); - const Real alpha_max = rhobar[m] / rho_min; + const Real alpha_max = robust::ratio(rhobar[m], rho_min); + if (alpha_max < vfrac[m]) { + // Despite our best efforts, we're already in the unstable regime (i.e. + // dPdV_T > 0) so we would actually want to *increase* the step instead + // of decreasing it. As a result, this code doesn't work as intended and + // should be skipped. + continue; + } if (scale * dx[m] > 0.5 * (alpha_max - vfrac[m])) { - scale = 0.5 * (alpha_max - vfrac[m]) / dx[m]; + scale = robust::ratio(0.5 * (alpha_max - vfrac[m]), dx[m]); } } // control how big of a step toward T = 0 is allowed if (scale * dx[nmat] < -0.95 * Tequil) { - scale = -0.95 * Tequil / dx[nmat]; + scale = robust::ratio(-0.95 * Tequil, dx[nmat]); } // Now apply the overall scaling for (int i = 0; i < neq; ++i) @@ -683,8 +707,10 @@ class PTESolverRhoT : public mix_impl::PTESolverBase { // Update the solution and return new residual. Possibly called repeatedly with // different scale factors as part of a line search PORTABLE_INLINE_FUNCTION - Real TestUpdate(const Real scale) { - if (scale == 1.0) { + Real TestUpdate(const Real scale, bool const cache_state = false) { + if (cache_state) { + // Store the current state in temp variables for first iteration of line + // search Ttemp = Tequil; for (int m = 0; m < nmat; ++m) vtemp[m] = vfrac[m]; @@ -692,15 +718,16 @@ class PTESolverRhoT : public mix_impl::PTESolverBase { Tequil = Ttemp + scale * dx[nmat]; for (int m = 0; m < nmat; ++m) { vfrac[m] = vtemp[m] + scale * dx[m]; - rho[m] = rhobar[m] / vfrac[m]; + rho[m] = robust::ratio(rhobar[m], vfrac[m]); u[m] = rhobar[m] * eos[m].InternalEnergyFromDensityTemperature( rho[m], Tnorm * Tequil, Cache[m]); - sie[m] = u[m] / rhobar[m]; - u[m] /= uscale; + sie[m] = robust::ratio(u[m], rhobar[m]); + u[m] = robust::ratio(u[m], uscale); temp[m] = Tequil; - press[m] = this->GetPressureFromPreferred(eos[m], rho[m], Tnorm * Tequil, sie[m], - Cache[m], false) / - uscale; + press[m] = + robust::ratio(this->GetPressureFromPreferred(eos[m], rho[m], Tnorm * Tequil, + sie[m], Cache[m], false), + uscale); } Residual(); return ResidualNorm(); @@ -766,7 +793,7 @@ class PTESolverFixedT : public mix_impl::PTESolverBase Tnorm = 1.0; // TODO(JCD): use whatever lambdas are passed in /*for (int m = 0; m < nmat; m++) { - if (lambda[m] != nullptr) Cache[m] = lambda[m]; + if (variadic_utils::is_nullptr(lambda[m])) Cache[m] = lambda[m]; }*/ } @@ -784,15 +811,15 @@ class PTESolverFixedT : public mix_impl::PTESolverBase // volume fractions have been potentially reset to ensure densitites are // larger than rho(Pmin(Tequil)); set the physical density to reflect // this change in volume fraction - rho[m] = rhobar[m] / vfrac[m]; + rho[m] = robust::ratio(rhobar[m], vfrac[m]); sie[m] = eos[m].InternalEnergyFromDensityTemperature(rho[m], Tequil, Cache[m]); uscale += sie[m] * rho[m]; // note the scaling of pressure press[m] = eos[m].PressureFromDensityTemperature(rho[m], Tequil, Cache[m]); } for (int m = 0; m < nmat; ++m) { - press[m] /= uscale; - u[m] = sie[m] * rhobar[m] / uscale; + press[m] = robust::ratio(press[m], uscale); + u[m] = sie[m] * robust::ratio(rhobar[m], uscale); } Residual(); return ResidualNorm(); @@ -838,11 +865,11 @@ class PTESolverFixedT : public mix_impl::PTESolverBase ////////////////////////////// Real dv = (vfrac[m] < 0.5 ? 1.0 : -1.0) * vfrac[m] * derivative_eps; const Real vf_pert = vfrac[m] + dv; - const Real rho_pert = rhobar[m] / vf_pert; + const Real rho_pert = robust::ratio(rhobar[m], vf_pert); - Real p_pert = - eos[m].PressureFromDensityTemperature(rho_pert, Tequil, Cache[m]) / uscale; - dpdv[m] = (p_pert - press[m]) / dv; + Real p_pert = robust::ratio( + eos[m].PressureFromDensityTemperature(rho_pert, Tequil, Cache[m]), uscale); + dpdv[m] = robust::ratio((p_pert - press[m]), dv); } // Fill in the Jacobian @@ -860,19 +887,27 @@ class PTESolverFixedT : public mix_impl::PTESolverBase PORTABLE_INLINE_FUNCTION Real ScaleDx() const { using namespace mix_params; + // Each check reduces the scale further if necessary Real scale = 1.0; // control how big of a step toward vfrac = 0 is allowed for (int m = 0; m < nmat; ++m) { if (scale * dx[m] < -vfrac_safety_fac * vfrac[m]) { - scale = -vfrac_safety_fac * vfrac[m] / dx[m]; + scale = robust::ratio(-vfrac_safety_fac * vfrac[m], dx[m]); } } // control how big of a step toward rho = rho(Pmin) is allowed for (int m = 0; m < nmat; m++) { const Real rho_min = eos[m].RhoPmin(Tequil); - const Real alpha_max = rhobar[m] / rho_min; + const Real alpha_max = robust::ratio(rhobar[m], rho_min); + if (alpha_max < vfrac[m]) { + // Despite our best efforts, we're already in the unstable regime (i.e. + // dPdV_T > 0) so we would actually want to *increase* the step instead + // of decreasing it. As a result, this code doesn't work as intended and + // should be skipped. + continue; + } if (scale * dx[m] > 0.5 * (alpha_max - vfrac[m])) { - scale = 0.5 * (alpha_max - vfrac[m]) / dx[m]; + scale = robust::ratio(0.5 * (alpha_max - vfrac[m]), dx[m]); } } // Now apply the overall scaling @@ -884,19 +919,22 @@ class PTESolverFixedT : public mix_impl::PTESolverBase // Update the solution and return new residual. Possibly called repeatedly with // different scale factors as part of a line search PORTABLE_INLINE_FUNCTION - Real TestUpdate(const Real scale) { - if (scale == 1.0) { + Real TestUpdate(const Real scale, bool const cache_state = false) { + if (cache_state) { + // Store the current state in temp variables for first iteration of line + // search for (int m = 0; m < nmat; ++m) vtemp[m] = vfrac[m]; } for (int m = 0; m < nmat; ++m) { vfrac[m] = vtemp[m] + scale * dx[m]; - rho[m] = rhobar[m] / vfrac[m]; + rho[m] = robust::ratio(rhobar[m], vfrac[m]); u[m] = rhobar[m] * eos[m].InternalEnergyFromDensityTemperature(rho[m], Tequil, Cache[m]); - sie[m] = u[m] / rhobar[m]; - u[m] /= uscale; - press[m] = eos[m].PressureFromDensityTemperature(rho[m], Tequil, Cache[m]) / uscale; + sie[m] = robust::ratio(u[m], rhobar[m]); + u[m] = robust::ratio(u[m], uscale); + press[m] = robust::ratio( + eos[m].PressureFromDensityTemperature(rho[m], Tequil, Cache[m]), uscale); } Residual(); return ResidualNorm(); @@ -963,7 +1001,7 @@ class PTESolverFixedP : public mix_impl::PTESolverBase Pequil = P; // TODO(JCD): use whatever lambdas are passed in /*for (int m = 0; m < nmat; m++) { - if (lambda[m] != nullptr) Cache[m] = lambda[m]; + if (variadic_utils::is_nullptr(lambda[m])) Cache[m] = lambda[m]; }*/ } @@ -990,8 +1028,9 @@ class PTESolverFixedP : public mix_impl::PTESolverBase // note the scaling of the material internal energy densities for (int m = 0; m < nmat; ++m) { - u[m] = sie[m] * rhobar[m] / uscale; - press[m] = eos[m].PressureFromDensityTemperature(rho[m], Tguess, Cache[m]) / uscale; + u[m] = robust::ratio(sie[m] * rhobar[m], uscale); + press[m] = robust::ratio( + eos[m].PressureFromDensityTemperature(rho[m], Tguess, Cache[m]), uscale); } Residual(); // Set the current guess for the equilibrium temperature. Note that this is already @@ -1006,7 +1045,7 @@ class PTESolverFixedP : public mix_impl::PTESolverBase Real vsum = 0.0; for (int m = 0; m < nmat; ++m) { vsum += vfrac[m]; - residual[m] = Pequil / uscale - press[m]; + residual[m] = robust::ratio(Pequil, uscale) - press[m]; } residual[nmat] = vfrac_total - vsum; } @@ -1036,23 +1075,25 @@ class PTESolverFixedP : public mix_impl::PTESolverBase ////////////////////////////// Real dv = (vfrac[m] < 0.5 ? 1.0 : -1.0) * vfrac[m] * derivative_eps; const Real vf_pert = vfrac[m] + dv; - const Real rho_pert = rhobar[m] / vf_pert; + const Real rho_pert = robust::ratio(rhobar[m], vf_pert); Real p_pert{}; Real e_pert{}; - p_pert = this->GetPressureFromPreferred(eos[m], rho_pert, Tnorm * Tequil, e_pert, - Cache[m], true) / - uscale; - dpdv[m] = (p_pert - press[m]) / dv; + p_pert = + robust::ratio(this->GetPressureFromPreferred(eos[m], rho_pert, Tnorm * Tequil, + e_pert, Cache[m], true), + uscale); + dpdv[m] = robust::ratio((p_pert - press[m]), dv); ////////////////////////////// // perturb temperature ////////////////////////////// Real dT = Tequil * derivative_eps; - p_pert = this->GetPressureFromPreferred(eos[m], rho[m], Tnorm * (Tequil + dT), - e_pert, Cache[m], true) / - uscale; - dpdT[m] = (p_pert - press[m]) / dT; + p_pert = robust::ratio(this->GetPressureFromPreferred(eos[m], rho[m], + Tnorm * (Tequil + dT), e_pert, + Cache[m], true), + uscale); + dpdT[m] = robust::ratio((p_pert - press[m]), dT); } // Fill in the Jacobian @@ -1070,11 +1111,12 @@ class PTESolverFixedP : public mix_impl::PTESolverBase PORTABLE_INLINE_FUNCTION Real ScaleDx() const { using namespace mix_params; + // Each check reduces the scale further if necessary Real scale = 1.0; // control how big of a step toward vfrac = 0 is allowed for (int m = 0; m < nmat; ++m) { if (scale * dx[m] < -vfrac_safety_fac * vfrac[m]) { - scale = -vfrac_safety_fac * vfrac[m] / dx[m]; + scale = -vfrac_safety_fac * robust::ratio(vfrac[m], dx[m]); } } const Real Tnew = Tequil + scale * dx[nmat]; @@ -1082,14 +1124,21 @@ class PTESolverFixedP : public mix_impl::PTESolverBase for (int m = 0; m < nmat; m++) { const Real rho_min = std::max(eos[m].RhoPmin(Tnorm * Tequil), eos[m].RhoPmin(Tnorm * Tnew)); - const Real alpha_max = rhobar[m] / rho_min; + const Real alpha_max = robust::ratio(rhobar[m], rho_min); + if (alpha_max < vfrac[m]) { + // Despite our best efforts, we're already in the unstable regime (i.e. + // dPdV_T > 0) so we would actually want to *increase* the step instead + // of decreasing it. As a result, this code doesn't work as intended and + // should be skipped. + continue; + } if (scale * dx[m] > 0.5 * (alpha_max - vfrac[m])) { - scale = 0.5 * (alpha_max - vfrac[m]) / dx[m]; + scale = 0.5 * robust::ratio(alpha_max - vfrac[m], dx[m]); } } // control how big of a step toward T = 0 is allowed if (scale * dx[nmat] < -0.95 * Tequil) { - scale = -0.95 * Tequil / dx[nmat]; + scale = -0.95 * robust::ratio(Tequil, dx[nmat]); } // Now apply the overall scaling for (int i = 0; i < neq; ++i) @@ -1100,8 +1149,10 @@ class PTESolverFixedP : public mix_impl::PTESolverBase // Update the solution and return new residual. Possibly called repeatedly with // different scale factors as part of a line search PORTABLE_INLINE_FUNCTION - Real TestUpdate(const Real scale) { - if (scale == 1.0) { + Real TestUpdate(const Real scale, bool const cache_state = false) { + if (cache_state) { + // Store the current state in temp variables for first iteration of line + // search Ttemp = Tequil; for (int m = 0; m < nmat; ++m) vtemp[m] = vfrac[m]; @@ -1109,13 +1160,14 @@ class PTESolverFixedP : public mix_impl::PTESolverBase Tequil = Ttemp + scale * dx[nmat]; for (int m = 0; m < nmat; ++m) { vfrac[m] = vtemp[m] + scale * dx[m]; - rho[m] = rhobar[m] / vfrac[m]; + rho[m] = robust::ratio(rhobar[m], vfrac[m]); u[m] = rhobar[m] * eos[m].InternalEnergyFromDensityTemperature( rho[m], Tnorm * Tequil, Cache[m]); - press[m] = eos[m].PressureFromDensityTemperature(rho[m], Tnorm * Tequil, Cache[m]) / - uscale; - sie[m] = u[m] / rhobar[m]; - u[m] /= uscale; + press[m] = robust::ratio( + eos[m].PressureFromDensityTemperature(rho[m], Tnorm * Tequil, Cache[m]), + uscale); + sie[m] = robust::ratio(u[m], rhobar[m]); + u[m] = robust::ratio(u[m], uscale); temp[m] = Tequil; } Residual(); @@ -1184,7 +1236,7 @@ class PTESolverRhoU : public mix_impl::PTESolverBase { utemp = AssignIncrement(scratch, nmat); // TODO(JCD): use whatever lambdas are passed in /*for (int m = 0; m < nmat; m++) { - if (lambda[m] != nullptr) Cache[m] = lambda[m]; + if (variadic_utils::is_nullptr(lambda[m])) Cache[m] = lambda[m]; }*/ } @@ -1228,7 +1280,7 @@ class PTESolverRhoU : public mix_impl::PTESolverBase { error_p += residual[m + 1] * residual[m + 1]; error_t += residual[m + nmat] * residual[m + nmat]; } - mean_t /= rho_total; + mean_t = robust::ratio(mean_t, rho_total); error_p = std::sqrt(error_p); error_t = std::sqrt(error_t); // Check for convergence @@ -1248,31 +1300,33 @@ class PTESolverRhoU : public mix_impl::PTESolverBase { ////////////////////////////// Real dv = (vfrac[m] < 0.5 ? 1.0 : -1.0) * vfrac[m] * derivative_eps; const Real vf_pert = vfrac[m] + dv; - const Real rho_pert = rhobar[m] / vf_pert; + const Real rho_pert = robust::ratio(rhobar[m], vf_pert); Real p_pert; - Real t_pert = - eos[m].TemperatureFromDensityInternalEnergy(rho_pert, sie[m], Cache[m]) / Tnorm; - p_pert = this->GetPressureFromPreferred(eos[m], rho_pert, Tnorm * t_pert, sie[m], - Cache[m], false) / - uscale; - dpdv[m] = (p_pert - press[m]) / dv; - dtdv[m] = (t_pert - temp[m]) / dv; + Real t_pert = robust::ratio( + eos[m].TemperatureFromDensityInternalEnergy(rho_pert, sie[m], Cache[m]), Tnorm); + p_pert = + robust::ratio(this->GetPressureFromPreferred(eos[m], rho_pert, Tnorm * t_pert, + sie[m], Cache[m], false), + uscale); + dpdv[m] = robust::ratio(p_pert - press[m], dv); + dtdv[m] = robust::ratio(t_pert - temp[m], dv); ////////////////////////////// // perturb energies ////////////////////////////// const Real de = std::abs(u[m]) * derivative_eps; - Real e_pert = (u[m] + de) / rhobar[m]; - - t_pert = - eos[m].TemperatureFromDensityInternalEnergy(rho[m], uscale * e_pert, Cache[m]) / - Tnorm; - p_pert = this->GetPressureFromPreferred(eos[m], rho[m], Tnorm * t_pert, - uscale * e_pert, Cache[m], false) / - uscale; - dpde[m] = (p_pert - press[m]) / de; - dtde[m] = (t_pert - temp[m]) / de; - if (std::abs(dtde[m]) < 1.e-16) { // must be on the cold curve + Real e_pert = robust::ratio(u[m] + de, rhobar[m]); + + t_pert = robust::ratio( + eos[m].TemperatureFromDensityInternalEnergy(rho[m], uscale * e_pert, Cache[m]), + Tnorm); + p_pert = + robust::ratio(this->GetPressureFromPreferred(eos[m], rho[m], Tnorm * t_pert, + uscale * e_pert, Cache[m], false), + uscale); + dpde[m] = robust::ratio(p_pert - press[m], de); + dtde[m] = robust::ratio(t_pert - temp[m], de); + if (std::abs(dtde[m]) < mix_params::min_dtde) { // must be on the cold curve dtde[m] = derivative_eps; } } @@ -1306,24 +1360,32 @@ class PTESolverRhoU : public mix_impl::PTESolverBase { PORTABLE_INLINE_FUNCTION Real ScaleDx() const { using namespace mix_params; + // Each check reduces the scale further if necessary Real scale = 1.0; for (int m = 0; m < nmat; ++m) { // control how big of a step toward vfrac = 0 is allowed if (scale * dx[m] < -0.1 * vfrac[m]) { - scale = -0.1 * vfrac[m] / dx[m]; + scale = -0.1 * robust::ratio(vfrac[m], dx[m]); } // try to control steps toward T = 0 const Real dt = (dtdv[m] * dx[m] + dtde[m] * dx[m + nmat]); if (scale * dt < -0.1 * temp[m]) { - scale = -0.1 * temp[m] / dt; + scale = -0.1 * robust::ratio(temp[m], dt); } const Real tt = temp[m] + scale * dt; const Real rho_min = std::max(eos[m].RhoPmin(Tnorm * temp[m]), eos[m].RhoPmin(Tnorm * tt)); - const Real alpha_max = rhobar[m] / rho_min; + const Real alpha_max = robust::ratio(rhobar[m], rho_min); // control how big of a step toward rho = rho(Pmin) is allowed + if (alpha_max < vfrac[m]) { + // Despite our best efforts, we're already in the unstable regime (i.e. + // dPdV_T > 0) so we would actually want to *increase* the step instead + // of decreasing it. As a result, this code doesn't work as intended and + // should be skipped. + continue; + } if (scale * dx[m] > 0.5 * (alpha_max - vfrac[m])) { - scale = 0.5 * (alpha_max - vfrac[m]) / dx[m]; + scale = 0.5 * robust::ratio(alpha_max - vfrac[m], dx[m]); } } // Now apply the overall scaling @@ -1335,8 +1397,10 @@ class PTESolverRhoU : public mix_impl::PTESolverBase { // Update the solution and return new residual. Possibly called repeatedly with // different scale factors as part of a line search PORTABLE_INLINE_FUNCTION - Real TestUpdate(const Real scale) const { - if (scale == 1.0) { + Real TestUpdate(const Real scale, bool const cache_state = false) const { + if (cache_state) { + // Store the current state in temp variables for first iteration of line + // search for (int m = 0; m < nmat; ++m) { vtemp[m] = vfrac[m]; utemp[m] = u[m]; @@ -1344,14 +1408,15 @@ class PTESolverRhoU : public mix_impl::PTESolverBase { } for (int m = 0; m < nmat; ++m) { vfrac[m] = vtemp[m] + scale * dx[m]; - rho[m] = rhobar[m] / vfrac[m]; + rho[m] = robust::ratio(rhobar[m], vfrac[m]); u[m] = utemp[m] + scale * dx[nmat + m]; - sie[m] = uscale * u[m] / rhobar[m]; - temp[m] = - eos[m].TemperatureFromDensityInternalEnergy(rho[m], sie[m], Cache[m]) / Tnorm; - press[m] = this->GetPressureFromPreferred(eos[m], rho[m], Tnorm * temp[m], sie[m], - Cache[m], false) / - uscale; + sie[m] = uscale * robust::ratio(u[m], rhobar[m]); + temp[m] = robust::ratio( + eos[m].TemperatureFromDensityInternalEnergy(rho[m], sie[m], Cache[m]), Tnorm); + press[m] = + robust::ratio(this->GetPressureFromPreferred(eos[m], rho[m], Tnorm * temp[m], + sie[m], Cache[m], false), + uscale); } Residual(); return ResidualNorm(); @@ -1390,25 +1455,28 @@ PORTABLE_INLINE_FUNCTION bool PTESolver(System &s) { // possibly scale the update to stay within reasonable bounds Real scale = s.ScaleDx(); - // const Real scale_save = scale; + PORTABLE_REQUIRE(scale <= 1.0, "PTE Solver is attempting to increase the step size"); // Line search Real gradfdx = -2.0 * scale * err; - scale = 1.0; + scale = 1.0; // New scale for line search Real err_old = err; - err = s.TestUpdate(scale); + // Test the update and reset the cache the current state + err = s.TestUpdate(scale, true /* cache_state */); if (err > err_old + line_search_alpha * gradfdx) { - // backtrack - Real err_mid = s.TestUpdate(0.5); + // backtrack to middle of step + scale = 0.5; + Real err_mid = s.TestUpdate(scale); if (err_mid < err && err_mid < err_old) { - scale = 0.75 + 0.5 * (err_mid - err) / (err - 2.0 * err_mid + err_old); - } else { - scale = line_search_fac; + // We know the half step is better than both the full step and the + // prior result, so try a pseudo parabolic fit to the error and find its + // minimum. The `scale` value is bound between 0.75 and 0.25. + scale = 0.75 + 0.5 * robust::ratio(err_mid - err, err - 2.0 * err_mid + err_old); } - for (int line_iter = 0; line_iter < line_search_max_iter; line_iter++) { err = s.TestUpdate(scale); if (err < err_old + line_search_alpha * scale * gradfdx) break; + // shrink the step if the error isn't reduced enough scale *= line_search_fac; } } diff --git a/singularity-eos/eos/default_variant.hpp b/singularity-eos/eos/default_variant.hpp new file mode 100644 index 0000000000..556c32bb8e --- /dev/null +++ b/singularity-eos/eos/default_variant.hpp @@ -0,0 +1,46 @@ +//------------------------------------------------------------------------------ +// © 2021-2024. Triad National Security, LLC. All rights reserved. This +// program was produced under U.S. Government contract 89233218CNA000001 +// for Los Alamos National Laboratory (LANL), which is operated by Triad +// National Security, LLC for the U.S. Department of Energy/National +// Nuclear Security Administration. All rights in the program are +// reserved by Triad National Security, LLC, and the U.S. Department of +// Energy/National Nuclear Security Administration. The Government is +// granted for itself and others acting on its behalf a nonexclusive, +// paid-up, irrevocable worldwide license in this material to reproduce, +// prepare derivative works, distribute copies to the public, perform +// publicly and display publicly, and to permit others to do so. +//------------------------------------------------------------------------------ + +#ifndef _SINGULARITY_EOS_EOS_DEFAULT_VARIANT_HPP_ +#define _SINGULARITY_EOS_EOS_DEFAULT_VARIANT_HPP_ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// Base stuff +#include +#include +#include + +// EOS models +#include +#include + +namespace singularity { + +// create the alias +using EOS = typename decltype(singularity::tl_to_Variant(singularity::combined_list))::vt; + +} // namespace singularity + +#endif // _SINGULARITY_EOS_EOS_DEFAULT_VARIANT_HPP_ diff --git a/singularity-eos/eos/eos.hpp.in b/singularity-eos/eos/eos.hpp.in new file mode 100644 index 0000000000..7d7cf9f939 --- /dev/null +++ b/singularity-eos/eos/eos.hpp.in @@ -0,0 +1,20 @@ +//------------------------------------------------------------------------------ +// © 2021-2024. Triad National Security, LLC. All rights reserved. This +// program was produced under U.S. Government contract 89233218CNA000001 +// for Los Alamos National Laboratory (LANL), which is operated by Triad +// National Security, LLC for the U.S. Department of Energy/National +// Nuclear Security Administration. All rights in the program are +// reserved by Triad National Security, LLC, and the U.S. Department of +// Energy/National Nuclear Security Administration. The Government is +// granted for itself and others acting on its behalf a nonexclusive, +// paid-up, irrevocable worldwide license in this material to reproduce, +// prepare derivative works, distribute copies to the public, perform +// publicly and display publicly, and to permit others to do so. +//------------------------------------------------------------------------------ + +#ifndef _SINGULARITY_EOS_EOS_EOS_HPP_ +#define _SINGULARITY_EOS_EOS_EOS_HPP_ + +#include <@SINGULARITY_VARIANT@> + +#endif // _SINGULARITY_EOS_EOS_EOS_HPP_ diff --git a/singularity-eos/eos/eos_carnahan_starling.hpp b/singularity-eos/eos/eos_carnahan_starling.hpp new file mode 100644 index 0000000000..b54bdb5242 --- /dev/null +++ b/singularity-eos/eos/eos_carnahan_starling.hpp @@ -0,0 +1,292 @@ +//------------------------------------------------------------------------------ +// © 2021-2024. Triad National Security, LLC. All rights reserved. This +// program was produced under U.S. Government contract 89233218CNA000001 +// for Los Alamos National Laboratory (LANL), which is operated by Triad +// National Security, LLC for the U.S. Department of Energy/National +// Nuclear Security Administration. All rights in the program are +// reserved by Triad National Security, LLC, and the U.S. Department of +// Energy/National Nuclear Security Administration. The Government is +// granted for itself and others acting on its behalf a nonexclusive, +// paid-up, irrevocable worldwide license in this material to reproduce, +// prepare derivative works, distribute copies to the public, perform +// publicly and display publicly, and to permit others to do so. +//------------------------------------------------------------------------------ + +#ifndef _SINGULARITY_EOS_EOS_EOS_CARNAHAN_STARLING_HPP_ +#define _SINGULARITY_EOS_EOS_EOS_CARNAHAN_STARLING_HPP_ + +// stdlib +#include +#include +#include + +// Ports-of-call +#include + +// Base stuff +#include +#include +#include +#include +#include +#include + +namespace singularity { + +using namespace eos_base; + +class CarnahanStarling : public EosBase { + public: + CarnahanStarling() = default; + PORTABLE_INLINE_FUNCTION CarnahanStarling(Real gm1, Real Cv, Real bb, Real qq) + : _Cv(Cv), _gm1(gm1), _bb(bb), _qq(qq), _T0(ROOM_TEMPERATURE), + _P0(ATMOSPHERIC_PRESSURE), _qp(0.0), + _rho0(DensityFromPressureTemperature(_P0, _T0)), _vol0(robust::ratio(1.0, _rho0)), + _sie0(Cv * _T0 + qq), + _bmod0(_rho0 * Cv * _T0 * + (PartialRhoZedFromDensity(_rho0) + + ZedFromDensity(_rho0) * ZedFromDensity(_rho0) * gm1)), + _dpde0(_rho0 * ZedFromDensity(_rho0) * gm1) { + checkParams(); + } + PORTABLE_INLINE_FUNCTION CarnahanStarling(Real gm1, Real Cv, Real bb, Real qq, Real qp, + Real T0, Real P0) + : _Cv(Cv), _gm1(gm1), _bb(bb), _qq(qq), _T0(T0), _P0(P0), _qp(qp), + _rho0(DensityFromPressureTemperature(P0, T0)), _vol0(robust::ratio(1.0, _rho0)), + _sie0(Cv * T0 + qq), + _bmod0(_rho0 * Cv * T0 * + (PartialRhoZedFromDensity(_rho0) + + ZedFromDensity(_rho0) * ZedFromDensity(_rho0) * gm1)), + _dpde0(_rho0 * ZedFromDensity(_rho0) * gm1) { + checkParams(); + } + CarnahanStarling GetOnDevice() { return *this; } + template + PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { + return std::max(robust::SMALL(), (sie - _qq) / _Cv); + } + PORTABLE_INLINE_FUNCTION void checkParams() const { + PORTABLE_ALWAYS_REQUIRE(_Cv >= 0, "Heat capacity must be positive"); + PORTABLE_ALWAYS_REQUIRE(_gm1 >= 0, "Gruneisen parameter must be positive"); + PORTABLE_ALWAYS_REQUIRE(_bb >= 0, "Covolume must be positive"); + } + template + PORTABLE_INLINE_FUNCTION Real ZedFromDensity( + const Real rho, Indexer_t &&lambda = static_cast(nullptr)) const { + const Real eta = _bb * rho; + const Real zed = + 1.0 + robust::ratio(eta * (4.0 - 2.0 * eta), math_utils::pow<3>(1.0 - eta)); + return zed; + } + template + PORTABLE_INLINE_FUNCTION Real PartialRhoZedFromDensity( + const Real rho, Indexer_t &&lambda = static_cast(nullptr)) const { + const Real eta = _bb * rho; + return 1.0 + robust::ratio(eta * (8.0 - 2.0 * eta), math_utils::pow<4>(1.0 - eta)); + } + template + PORTABLE_INLINE_FUNCTION Real DensityFromPressureTemperature( + const Real press, const Real temperature, const Real guess = robust::SMALL(), + Indexer_t &&lambda = static_cast(nullptr)) const { + Real real_root; + auto poly = [=](Real dens) { + return _Cv * temperature * _gm1 * dens * ZedFromDensity(dens); + }; + using RootFinding1D::findRoot; + using RootFinding1D::Status; + static constexpr Real xtol = 1.0e-12; + static constexpr Real ytol = 1.0e-12; + static constexpr Real lo_bound = robust::SMALL(); + const Real hi_bound = robust::ratio(1.0, _bb); + auto status = findRoot(poly, press, guess, lo_bound, hi_bound, xtol, ytol, real_root); + if (status != Status::SUCCESS) { + // Root finder failed even though the solution was bracketed... this is an error + EOS_ERROR("*** (Warning) DensityFromPressureTemperature :: Convergence not met in " + "Carnahan-Starling EoS (root finder util) ***\n"); + real_root = -1.0; + } + return std::max(robust::SMALL(), real_root); + } + template + PORTABLE_INLINE_FUNCTION Real InternalEnergyFromDensityTemperature( + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { + return std::max(_qq, _Cv * temperature + _qq); + } + template + PORTABLE_INLINE_FUNCTION Real PressureFromDensityTemperature( + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { + const Real zed = ZedFromDensity(rho); + return std::max(robust::SMALL(), zed * rho * temperature * _Cv * _gm1); + } + template + PORTABLE_INLINE_FUNCTION Real PressureFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { + const Real zed = ZedFromDensity(rho); + return std::max(robust::SMALL(), zed * rho * (sie - _qq) * _gm1); + } + template + PORTABLE_INLINE_FUNCTION Real + EntropyFromDensityTemperature(const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { + const Real vol = robust::ratio(1.0, rho); + const Real one_by_vb = robust::ratio(1.0, vol - _bb); + const Real one_by_v0b = robust::ratio(1.0, _vol0 - _bb); + return _Cv * std::log(robust::ratio(temperature, _T0) + robust::SMALL()) + + _gm1 * _Cv * std::log(robust::ratio(vol, _vol0) + robust::SMALL()) - + _gm1 * _Cv * _bb * (one_by_vb - one_by_v0b) * + (4.0 + _bb * (one_by_vb + one_by_v0b)) + + _qp; + } + template + PORTABLE_INLINE_FUNCTION Real EntropyFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { + const Real vol = robust::ratio(1.0, rho); + const Real one_by_vb = robust::ratio(1.0, vol - _bb); + const Real one_by_v0b = robust::ratio(1.0, _vol0 - _bb); + return _Cv * std::log(robust::ratio(sie - _qq, _sie0 - _qq) + robust::SMALL()) + + _gm1 * _Cv * std::log(robust::ratio(vol, _vol0) + robust::SMALL()) - + _gm1 * _Cv * _bb * (one_by_vb - one_by_v0b) * + (4.0 + _bb * (one_by_vb + one_by_v0b)) + + _qp; + } + template + PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityTemperature( + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { + return _Cv; + } + template + PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { + return _Cv; + } + template + PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityTemperature( + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { + return std::max(robust::SMALL(), + rho * _Cv * temperature * _gm1 * + (PartialRhoZedFromDensity(rho) + + ZedFromDensity(rho) * ZedFromDensity(rho) * _gm1)); + } + template + PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { + return std::max(robust::SMALL(), + rho * (sie - _qq) * _gm1 * + (PartialRhoZedFromDensity(rho) + + ZedFromDensity(rho) * ZedFromDensity(rho) * _gm1)); + } + template + PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityTemperature( + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { + return ZedFromDensity(rho) * _gm1; + } + template + PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { + return ZedFromDensity(rho) * _gm1; + } + template + PORTABLE_INLINE_FUNCTION Real MinInternalEnergyFromDensity( + const Real rho, Indexer_t &&lambda = static_cast(nullptr)) const { + return _qq; + } + template + PORTABLE_INLINE_FUNCTION void + FillEos(Real &rho, Real &temp, Real &energy, Real &press, Real &cv, Real &bmod, + const unsigned long output, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION void + ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, + Real &bmod, Real &dpde, Real &dvdt, + Indexer_t &&lambda = static_cast(nullptr)) const { + // use STP: 1 atmosphere, room temperature + rho = _rho0; + temp = _T0; + sie = _sie0; + press = _P0; + cv = _Cv; + bmod = _bmod0; + dpde = _dpde0; + } + // Generic functions provided by the base class. These contain e.g. the vector + // overloads that use the scalar versions declared here + SG_ADD_BASE_CLASS_USINGS(CarnahanStarling) + PORTABLE_INLINE_FUNCTION + int nlambda() const noexcept { return 0; } + static constexpr unsigned long PreferredInput() { return _preferred_input; } + static inline unsigned long scratch_size(std::string method, unsigned int nelements) { + return 0; + } + static inline unsigned long max_scratch_size(unsigned int nelements) { return 0; } + PORTABLE_INLINE_FUNCTION void PrintParams() const { + printf("Carnahan-Starling Parameters:\nGamma = %g\nCv = %g\nb = %g\nq = " + "%g\n", + _gm1 + 1.0, _Cv, _bb, _qq); + } + template + PORTABLE_INLINE_FUNCTION void + DensityEnergyFromPressureTemperature(const Real press, const Real temp, + Indexer_t &&lambda, Real &rho, Real &sie) const { + sie = std::max(_qq, _Cv * temp + _qq); + rho = DensityFromPressureTemperature(press, temp); + } + inline void Finalize() {} + static std::string EosType() { return std::string("CarnahanStarling"); } + static std::string EosPyType() { return EosType(); } + + private: + Real _Cv, _gm1, _bb, _qq; + // optional reference state variables + Real _T0, _P0, _qp; + // reference values + Real _rho0, _vol0, _sie0, _bmod0, _dpde0; + // static constexpr const Real _T0 = ROOM_TEMPERATURE; + // static constexpr const Real _P0 = ATMOSPHERIC_PRESSURE; + static constexpr const unsigned long _preferred_input = + thermalqs::density | thermalqs::specific_internal_energy; +}; +template +PORTABLE_INLINE_FUNCTION void CarnahanStarling::FillEos(Real &rho, Real &temp, Real &sie, + Real &press, Real &cv, Real &bmod, + const unsigned long output, + Indexer_t &&lambda) const { + if (output & thermalqs::density && output & thermalqs::specific_internal_energy) { + if (output & thermalqs::pressure || output & thermalqs::temperature) { + UNDEFINED_ERROR; + } + DensityEnergyFromPressureTemperature(press, temp, lambda, rho, sie); + } + if (output & thermalqs::pressure && output & thermalqs::specific_internal_energy) { + if (output & thermalqs::density || output & thermalqs::temperature) { + UNDEFINED_ERROR; + } + sie = InternalEnergyFromDensityTemperature(rho, temp, lambda); + } + if (output & thermalqs::temperature && output & thermalqs::specific_internal_energy) { + sie = robust::ratio(press, ZedFromDensity(rho) * rho * _gm1) + _qq; + } + if (output & thermalqs::pressure) press = PressureFromDensityInternalEnergy(rho, sie); + if (output & thermalqs::temperature) + temp = TemperatureFromDensityInternalEnergy(rho, sie); + if (output & thermalqs::bulk_modulus) + bmod = BulkModulusFromDensityInternalEnergy(rho, sie); + if (output & thermalqs::specific_heat) + cv = SpecificHeatFromDensityInternalEnergy(rho, sie); +} + +} // namespace singularity + +#endif // _SINGULARITY_EOS_EOS_EOS_CARNAHAN_STARLING_HPP_ diff --git a/singularity-eos/eos/eos_davis.hpp b/singularity-eos/eos/eos_davis.hpp index c24b826821..fb34c2a229 100644 --- a/singularity-eos/eos/eos_davis.hpp +++ b/singularity-eos/eos/eos_davis.hpp @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// © 2021-2023. Triad National Security, LLC. All rights reserved. This +// © 2021-2024. Triad National Security, LLC. All rights reserved. This // program was produced under U.S. Government contract 89233218CNA000001 // for Los Alamos National Laboratory (LANL), which is operated by Triad // National Security, LLC for the U.S. Department of Energy/National @@ -18,8 +18,10 @@ #include #include +#include #include #include +#include #include #include @@ -37,80 +39,120 @@ class DavisReactants : public EosBase { : _rho0(rho0), _e0(e0), _P0(P0), _T0(T0), _A(A), _B(B), _C(C), _G0(G0), _Z(Z), _alpha(alpha), _Cv0(Cv0) {} DavisReactants GetOnDevice() { return *this; } + template PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { - const Real es = Es(rho); - const Real tmp = std::pow((1.0 + _alpha) / (Ts(rho) * _Cv0) * (sie - es) + 1.0, - 1.0 / (1.0 + _alpha)); - if (tmp > 0) return Ts(rho) * tmp; - return Ts(rho) + (sie - es) / _Cv0; // This branch is a negative temperature - } + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { + const Real power_base = DimlessEdiff(rho, sie); + if (power_base <= 0) { + // This case would result in an imaginary temperature (i.e. negative), but we won't + // allow that so return zero + return 0.; + } + const Real tmp = std::pow(power_base, 1.0 / (1.0 + _alpha)); + return Ts(rho) * tmp; + } + template PORTABLE_INLINE_FUNCTION Real InternalEnergyFromDensityTemperature( - const Real rho, const Real temp, Real *lambda = nullptr) const { + const Real rho, const Real temp, + Indexer_t &&lambda = static_cast(nullptr)) const { const Real t_s = Ts(rho); + PORTABLE_REQUIRE(temp >= 0, "Negative temperature provided"); return Es(rho) + _Cv0 * t_s / (1.0 + _alpha) * (std::pow(temp / t_s, 1.0 + _alpha) - 1.0); } + template PORTABLE_INLINE_FUNCTION Real PressureFromDensityTemperature( - const Real rho, const Real temp, Real *lambda = nullptr) const { + const Real rho, const Real temp, + Indexer_t &&lambda = static_cast(nullptr)) const { return PressureFromDensityInternalEnergy( rho, InternalEnergyFromDensityTemperature(rho, temp)); } + template PORTABLE_INLINE_FUNCTION Real PressureFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { return Ps(rho) + Gamma(rho) * rho * (sie - Es(rho)); } - PORTABLE_INLINE_FUNCTION Real - MinInternalEnergyFromDensity(const Real rho, Real *lambda = nullptr) const { - MinInternalEnergyIsNotEnabled("DavisReactants"); - return 0.0; + template + PORTABLE_INLINE_FUNCTION Real MinInternalEnergyFromDensity( + const Real rho, Indexer_t &&lambda = static_cast(nullptr)) const { + // Minimum enegy is when the returned temperature is zero. This only happens + // when the base to the exponent is zero (see T(rho, e) equation) + const Real es = Es(rho); + const Real ts = Ts(rho); + return es - (_Cv0 * ts) / (1 + _alpha); } - PORTABLE_INLINE_FUNCTION Real EntropyFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + template + PORTABLE_INLINE_FUNCTION Real + EntropyFromDensityTemperature(const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { EntropyIsNotEnabled("DavisReactants"); return 1.0; } + template PORTABLE_INLINE_FUNCTION Real EntropyFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { EntropyIsNotEnabled("DavisReactants"); return 1.0; } + template PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityTemperature( - const Real rho, const Real temp, Real *lambda = nullptr) const { + const Real rho, const Real temp, + Indexer_t &&lambda = static_cast(nullptr)) const { return SpecificHeatFromDensityInternalEnergy( rho, InternalEnergyFromDensityTemperature(rho, temp)); } + template PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { - return _Cv0 / std::pow((1 + _alpha) / (Ts(rho) * _Cv0) * (sie - Es(rho)) + 1, - -_alpha / (1 + _alpha)); - } + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { + const Real power_base = DimlessEdiff(rho, sie); + if (power_base <= 0) { + // Return zero heat capacity instead of an imaginary value + return 0.; + } + return _Cv0 / std::pow(power_base, -_alpha / (1 + _alpha)); + } + template PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityTemperature( - const Real rho, const Real temp, Real *lambda = nullptr) const { + const Real rho, const Real temp, + Indexer_t &&lambda = static_cast(nullptr)) const { return BulkModulusFromDensityInternalEnergy( rho, InternalEnergyFromDensityTemperature(rho, temp)); } + template PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const; + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { return Gamma(rho); } + template PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { return Gamma(rho); } - PORTABLE_INLINE_FUNCTION void FillEos(Real &rho, Real &temp, Real &energy, Real &press, - Real &cv, Real &bmod, const unsigned long output, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - void ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, - Real &bmod, Real &dpde, Real &dvdt, - Real *lambda = nullptr) const; + template + PORTABLE_INLINE_FUNCTION void + FillEos(Real &rho, Real &temp, Real &energy, Real &press, Real &cv, Real &bmod, + const unsigned long output, + Indexer_t &&lambda = static_cast(nullptr)) const; + template PORTABLE_INLINE_FUNCTION void - DensityEnergyFromPressureTemperature(const Real press, const Real temp, Real *lambda, - Real &rho, Real &sie) const; + ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, + Real &bmod, Real &dpde, Real &dvdt, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION void + DensityEnergyFromPressureTemperature(const Real press, const Real temp, + Indexer_t &&lambda, Real &rho, Real &sie) const; // Generic functions provided by the base class. These contain e.g. the vector // overloads that use the scalar versions declared here SG_ADD_BASE_CLASS_USINGS(DavisReactants) @@ -137,6 +179,7 @@ class DavisReactants : public EosBase { // static constexpr const char _eos_type[] = "DavisReactants"; static constexpr unsigned long _preferred_input = thermalqs::density | thermalqs::specific_internal_energy; + PORTABLE_FORCEINLINE_FUNCTION Real DimlessEdiff(const Real rho, const Real sie) const; PORTABLE_INLINE_FUNCTION Real Ps(const Real rho) const; PORTABLE_INLINE_FUNCTION Real Es(const Real rho) const; PORTABLE_INLINE_FUNCTION Real Ts(const Real rho) const; @@ -148,74 +191,103 @@ class DavisProducts : public EosBase { DavisProducts() = default; PORTABLE_INLINE_FUNCTION DavisProducts(const Real a, const Real b, const Real k, const Real n, const Real vc, - const Real pc, const Real Cv, const Real E0) - : _a(a), _b(b), _k(k), _n(n), _vc(vc), _pc(pc), _Cv(Cv), _E0(E0) {} + const Real pc, const Real Cv) + : _a(a), _b(b), _k(k), _n(n), _vc(vc), _pc(pc), _Cv(Cv) {} DavisProducts GetOnDevice() { return *this; } + template PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { return Ts(rho) + (sie - Es(rho)) / _Cv; } + template PORTABLE_INLINE_FUNCTION Real InternalEnergyFromDensityTemperature( - const Real rho, const Real temp, Real *lambda = nullptr) const { + const Real rho, const Real temp, + Indexer_t &&lambda = static_cast(nullptr)) const { return _Cv * (temp - Ts(rho)) + Es(rho); } + template PORTABLE_INLINE_FUNCTION Real PressureFromDensityTemperature( - const Real rho, const Real temp, Real *lambda = nullptr) const { + const Real rho, const Real temp, + Indexer_t &&lambda = static_cast(nullptr)) const { return PressureFromDensityInternalEnergy( rho, InternalEnergyFromDensityTemperature(rho, temp)); } + template PORTABLE_INLINE_FUNCTION Real PressureFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { return Ps(rho) + rho * Gamma(rho) * (sie - Es(rho)); } - PORTABLE_INLINE_FUNCTION Real - MinInternalEnergyFromDensity(const Real rho, Real *lambda = nullptr) const { + template + PORTABLE_INLINE_FUNCTION Real MinInternalEnergyFromDensity( + const Real rho, Indexer_t &&lambda = static_cast(nullptr)) const { MinInternalEnergyIsNotEnabled("DavisProducts"); return 0.0; } - PORTABLE_INLINE_FUNCTION Real EntropyFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + template + PORTABLE_INLINE_FUNCTION Real + EntropyFromDensityTemperature(const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { EntropyIsNotEnabled("DavisProducts"); return 1.0; } + template PORTABLE_INLINE_FUNCTION Real EntropyFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { EntropyIsNotEnabled("DavisProducts"); return 1.0; } + template PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { return _Cv; } + template PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { return _Cv; } + template PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityTemperature( - const Real rho, const Real temp, Real *lambda = nullptr) const { + const Real rho, const Real temp, + Indexer_t &&lambda = static_cast(nullptr)) const { return BulkModulusFromDensityInternalEnergy( rho, InternalEnergyFromDensityTemperature(rho, temp)); } + template PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const; + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { return Gamma(rho); } + template PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { return Gamma(rho); } + template PORTABLE_INLINE_FUNCTION void - DensityEnergyFromPressureTemperature(const Real press, const Real temp, Real *lambda, - Real &rho, Real &sie) const; - PORTABLE_INLINE_FUNCTION void FillEos(Real &rho, Real &temp, Real &energy, Real &press, - Real &cv, Real &bmod, const unsigned long output, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - void ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, - Real &bmod, Real &dpde, Real &dvdt, - Real *lambda = nullptr) const; + DensityEnergyFromPressureTemperature(const Real press, const Real temp, + Indexer_t &&lambda, Real &rho, Real &sie) const; + template + PORTABLE_INLINE_FUNCTION void + FillEos(Real &rho, Real &temp, Real &energy, Real &press, Real &cv, Real &bmod, + const unsigned long output, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION void + ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, + Real &bmod, Real &dpde, Real &dvdt, + Indexer_t &&lambda = static_cast(nullptr)) const; // Generic functions provided by the base class. These contain e.g. the vector // overloads that use the scalar versions declared here SG_ADD_BASE_CLASS_USINGS(DavisProducts) @@ -228,8 +300,8 @@ class DavisProducts : public EosBase { static inline unsigned long max_scratch_size(unsigned int nelements) { return 0; } PORTABLE_INLINE_FUNCTION void PrintParams() const { static constexpr char s1[]{"DavisProducts Params: "}; - printf("%sa:%e b:%e k:%e\nn:%e vc:%e pc:%e\nCv:%e E0:%e\n", s1, _a, _b, _k, _n, _vc, - _pc, _Cv, _E0); + printf("%sa:%e b:%e k:%e\nn:%e vc:%e pc:%e\nCv:%e \n", s1, _a, _b, _k, _n, _vc, _pc, + _Cv); } inline void Finalize() {} static std::string EosType() { return std::string("DavisProducts"); } @@ -237,20 +309,29 @@ class DavisProducts : public EosBase { private: static constexpr Real onethird = 1.0 / 3.0; - Real _a, _b, _k, _n, _vc, _pc, _Cv, _E0; + Real _a, _b, _k, _n, _vc, _pc, _Cv; // static constexpr const char _eos_type[] = "DavisProducts"; static constexpr const unsigned long _preferred_input = thermalqs::density | thermalqs::specific_internal_energy; PORTABLE_INLINE_FUNCTION Real F(const Real rho) const { + if (rho <= 0) { + return 0.; + } const Real vvc = 1.0 / (rho * _vc); return 2.0 * _a / (std::pow(vvc, 2 * _n) + 1.0); } PORTABLE_INLINE_FUNCTION Real Ps(const Real rho) const { + if (rho <= 0) { + return 0.; + } const Real vvc = 1 / (rho * _vc); return _pc * std::pow(0.5 * (std::pow(vvc, _n) + std::pow(vvc, -_n)), _a / _n) / std::pow(vvc, _k + _a) * (_k - 1.0 + F(rho)) / (_k - 1.0 + _a); } PORTABLE_INLINE_FUNCTION Real Es(const Real rho) const { + if (rho <= 0) { + return 0.; + } const Real vvc = 1 / (rho * _vc); const Real ec = _pc * _vc / (_k - 1.0 + _a); // const Real de = ecj-(Es(rho0)-_E0); @@ -258,6 +339,9 @@ class DavisProducts : public EosBase { std::pow(vvc, _k - 1.0 + _a); } PORTABLE_INLINE_FUNCTION Real Ts(const Real rho) const { + if (rho <= 0) { + return 0.; + } const Real vvc = 1 / (rho * _vc); return std::pow(2.0, -_a * _b / _n) * _pc * _vc / (_Cv * (_k - 1 + _a)) * std::pow(0.5 * (std::pow(vvc, _n) + std::pow(vvc, -_n)), _a / _n * (1 - _b)) / @@ -268,9 +352,14 @@ class DavisProducts : public EosBase { } }; +PORTABLE_FORCEINLINE_FUNCTION Real DavisReactants::DimlessEdiff(const Real rho, + const Real sie) const { + return (1.0 + _alpha) / (Ts(rho) * _Cv0) * (sie - Es(rho)) + 1.0; +} + PORTABLE_INLINE_FUNCTION Real DavisReactants::Ps(const Real rho) const { using namespace math_utils; - const Real y = 1.0 - _rho0 / rho; + const Real y = 1.0 - robust::ratio(_rho0, std::max(rho, 0.)); const Real phat = 0.25 * _A * _A / _B * _rho0; const Real b4y = 4.0 * _B * y; @@ -284,7 +373,7 @@ PORTABLE_INLINE_FUNCTION Real DavisReactants::Ps(const Real rho) const { } } PORTABLE_INLINE_FUNCTION Real DavisReactants::Es(const Real rho) const { - const Real y = 1 - _rho0 / rho; + const Real y = 1 - robust::ratio(_rho0, std::max(rho, 0.)); const Real phat = 0.25 * _A * _A / _B * _rho0; const Real b4y = 4 * _B * y; Real e_s; @@ -296,33 +385,32 @@ PORTABLE_INLINE_FUNCTION Real DavisReactants::Es(const Real rho) const { } else { e_s = -y - (1.0 - std::exp(b4y)) / (4.0 * _B); } - return _e0 + _P0 * (1.0 / _rho0 - 1.0 / rho) + phat / _rho0 * e_s; + return _e0 + _P0 * (1.0 / _rho0 - robust::ratio(1.0, std::max(rho, 0.))) + + phat / _rho0 * e_s; } PORTABLE_INLINE_FUNCTION Real DavisReactants::Ts(const Real rho) const { - if (rho >= _rho0) { - const Real y = 1 - _rho0 / rho; - return _T0 * std::exp(-_Z * y) * std::pow(_rho0 / rho, -_G0 - _Z); - } else { - return _T0 * std::pow(_rho0 / rho, -_G0); - } + const Real rho0overrho = robust::ratio(_rho0, std::max(rho, 0.)); + const Real y = 1 - rho0overrho; + return _T0 * std::exp(-_Z * y) * std::pow(rho0overrho, -_G0 - _Z); } PORTABLE_INLINE_FUNCTION Real DavisReactants::Gamma(const Real rho) const { if (rho >= _rho0) { - const Real y = 1 - _rho0 / rho; + const Real y = 1 - robust::ratio(_rho0, std::max(rho, 0.)); return _G0 + _Z * y; } else { return _G0; } } +template PORTABLE_INLINE_FUNCTION Real DavisReactants::BulkModulusFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda) const { + const Real rho, const Real sie, Indexer_t &&lambda) const { using namespace math_utils; - const Real y = 1 - _rho0 / rho; + const Real y = 1 - robust::ratio(_rho0, std::max(rho, 0.)); const Real phat = 0.25 * _A * _A / _B * _rho0; const Real b4y = 4 * _B * y; - const Real gamma = Gamma(rho); - const Real esv = -Ps(rho); + const Real gamma = Gamma(std::max(rho, 0.)); + const Real esv = -Ps(std::max(rho, 0.)); const Real psv = (rho >= _rho0) ? -phat * _rho0 * @@ -330,17 +418,21 @@ PORTABLE_INLINE_FUNCTION Real DavisReactants::BulkModulusFromDensityInternalEner 3 * y / pow<4>(1 - y) + 4 * pow<2>(y) / pow<5>(1 - y)) : -phat * 4 * _B * _rho0 * std::exp(b4y); const Real gammav = (rho >= _rho0) ? _Z * _rho0 : 0.0; - return -(psv + (sie - Es(rho)) * rho * (gammav - gamma * rho) - gamma * rho * esv) / - rho; + const Real numerator = + -(psv + (sie - Es(rho)) * std::max(rho, 0.) * (gammav - gamma * std::max(rho, 0.)) - + gamma * std::max(rho, 0.) * esv); + return robust::ratio(numerator, std::max(rho, 0.)); } +template PORTABLE_INLINE_FUNCTION void DavisReactants::DensityEnergyFromPressureTemperature( - const Real press, const Real temp, Real *lambda, Real &rho, Real &sie) const { + const Real press, const Real temp, Indexer_t &&lambda, Real &rho, Real &sie) const { // First, solve P=P(rho,T) for rho. Note P(rho,e) has an sie-es term, which is only a // function of T + PORTABLE_REQUIRE(temp >= 0, "Negative temperature provided"); auto PofRatT = [&](const Real r) { return (Ps(r) + Gamma(r) * r * _Cv0 * Ts(r) / (1 + _alpha) * - (std::pow(temp / Ts(r), 1 + _alpha) - 1.0)); + (std::pow(robust::ratio(temp, Ts(r)), 1 + _alpha) - 1.0)); }; using RootFinding1D::regula_falsi; using RootFinding1D::Status; @@ -350,12 +442,19 @@ PORTABLE_INLINE_FUNCTION void DavisReactants::DensityEnergyFromPressureTemperatu EOS_ERROR("DavisReactants::DensityEnergyFromPressureTemperature: " "Root find failed to find a solution given P, T\n"); } + if (rho < 0.) { + EOS_ERROR("DavisReactants::DensityEnergyFromPressureTemperature: " + "Root find resulted in a negative density\n"); + } sie = InternalEnergyFromDensityTemperature(rho, temp); } -PORTABLE_INLINE_FUNCTION -void DavisReactants::FillEos(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, - Real &bmod, const unsigned long output, Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION void DavisReactants::FillEos(Real &rho, Real &temp, Real &sie, + Real &press, Real &cv, Real &bmod, + const unsigned long output, + Indexer_t &&lambda) const { + // BROKEN: This can only handle density-energy inputs! MUST BE CHANGED if (output & thermalqs::pressure) press = PressureFromDensityInternalEnergy(rho, sie); if (output & thermalqs::temperature) temp = TemperatureFromDensityInternalEnergy(rho, sie); @@ -367,10 +466,11 @@ void DavisReactants::FillEos(Real &rho, Real &temp, Real &sie, Real &press, Real // TODO: Chad please decide if this is sane // TODO(JMM): Pre-cache values instead of computing inline -PORTABLE_INLINE_FUNCTION -void DavisReactants::ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, - Real &cv, Real &bmod, Real &dpde, Real &dvdt, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION void +DavisReactants::ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, + Real &cv, Real &bmod, Real &dpde, Real &dvdt, + Indexer_t &&lambda) const { rho = _rho0; temp = _T0; sie = InternalEnergyFromDensityTemperature(_rho0, _T0); @@ -383,9 +483,13 @@ void DavisReactants::ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Re dvdt = gm1 * cv / bmod; } +template PORTABLE_INLINE_FUNCTION Real DavisProducts::BulkModulusFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda) const { + const Real rho, const Real sie, Indexer_t &&lambda) const { using namespace math_utils; + if (rho <= 0) { + return 0.; + } const Real vvc = 1 / (rho * _vc); const Real Fx = -4 * _a * std::pow(vvc, 2 * _n - 1) / pow<2>(1 + std::pow(vvc, 2 * _n)); const Real tmp = std::pow(0.5 * (std::pow(vvc, _n) + std::pow(vvc, -_n)), _a / _n) / @@ -403,8 +507,10 @@ PORTABLE_INLINE_FUNCTION Real DavisProducts::BulkModulusFromDensityInternalEnerg return -(psv + (sie - Es(rho)) * rho * (gammav - gamma * rho) - gamma * rho * esv) / rho; } +template PORTABLE_INLINE_FUNCTION void DavisProducts::DensityEnergyFromPressureTemperature( - const Real press, const Real temp, Real *lambda, Real &rho, Real &sie) const { + const Real press, const Real temp, Indexer_t &&lambda, Real &rho, Real &sie) const { + PORTABLE_REQUIRE(temp >= 0, "Negative temperature provided"); auto PofRatT = [&](const Real r) { return (Ps(r) + Gamma(r) * r * _Cv * (temp - Ts(r))); }; @@ -417,11 +523,17 @@ PORTABLE_INLINE_FUNCTION void DavisProducts::DensityEnergyFromPressureTemperatur EOS_ERROR("DavisProducts::DensityEnergyFromPressureTemperature: " "Root find failed to find a solution given P, T\n"); } + if (rho < 0.) { + EOS_ERROR("DavisReactants::DensityEnergyFromPressureTemperature: " + "Root find resulted in a negative density\n"); + } sie = InternalEnergyFromDensityTemperature(rho, temp); } -PORTABLE_INLINE_FUNCTION -void DavisProducts::FillEos(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, - Real &bmod, const unsigned long output, Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION void +DavisProducts::FillEos(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, + Real &bmod, const unsigned long output, Indexer_t &&lambda) const { + // BROKEN: This can only handle density-energy inputs! MUST BE CHANGED if (output & thermalqs::pressure) press = PressureFromDensityInternalEnergy(rho, sie); if (output & thermalqs::temperature) temp = TemperatureFromDensityInternalEnergy(rho, sie); @@ -432,10 +544,11 @@ void DavisProducts::FillEos(Real &rho, Real &temp, Real &sie, Real &press, Real } // TODO: pre-cache values instead of computing them // TODO: chad please decide if these choices are sane -PORTABLE_INLINE_FUNCTION -void DavisProducts::ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, - Real &cv, Real &bmod, Real &dpde, Real &dvdt, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION void +DavisProducts::ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, + Real &cv, Real &bmod, Real &dpde, Real &dvdt, + Indexer_t &&lambda) const { rho = 1.0 / _vc; sie = 2. * Es(rho); temp = TemperatureFromDensityInternalEnergy(rho, sie); diff --git a/singularity-eos/eos/eos_eospac.hpp b/singularity-eos/eos/eos_eospac.hpp index c6bd2d1604..343d72690b 100644 --- a/singularity-eos/eos/eos_eospac.hpp +++ b/singularity-eos/eos/eos_eospac.hpp @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// © 2021-2023. Triad National Security, LLC. All rights reserved. This +// © 2021-2024. Triad National Security, LLC. All rights reserved. This // program was produced under U.S. Government contract 89233218CNA000001 // for Los Alamos National Laboratory (LANL), which is operated by Triad // National Security, LLC for the U.S. Department of Energy/National @@ -142,57 +142,86 @@ class EOSPAC : public EosBase { bool linear_interp = false); inline EOSPAC GetOnDevice() { return *this; } SG_PIF_NOWARN + template PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const; + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; SG_PIF_NOWARN + template PORTABLE_INLINE_FUNCTION Real InternalEnergyFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const; + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const; SG_PIF_NOWARN - PORTABLE_INLINE_FUNCTION Real PressureFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const; + template + PORTABLE_INLINE_FUNCTION Real + PressureFromDensityTemperature(const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const; SG_PIF_NOWARN + template PORTABLE_INLINE_FUNCTION Real PressureFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const; + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; SG_PIF_NOWARN - PORTABLE_INLINE_FUNCTION Real - MinInternalEnergyFromDensity(const Real rho, Real *lambda = nullptr) const; + template + PORTABLE_INLINE_FUNCTION Real MinInternalEnergyFromDensity( + const Real rho, Indexer_t &&lambda = static_cast(nullptr)) const; SG_PIF_NOWARN - PORTABLE_INLINE_FUNCTION Real EntropyFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const; + template + PORTABLE_INLINE_FUNCTION Real + EntropyFromDensityTemperature(const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const; SG_PIF_NOWARN + template PORTABLE_INLINE_FUNCTION Real EntropyFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const; + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; SG_PIF_NOWARN + template PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const; + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const; SG_PIF_NOWARN + template PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const; + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; SG_PIF_NOWARN + template PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const; + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const; SG_PIF_NOWARN + template PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const; + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; SG_PIF_NOWARN + template PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const; + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const; SG_PIF_NOWARN + template PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const; + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; SG_PIF_NOWARN - PORTABLE_INLINE_FUNCTION void FillEos(Real &rho, Real &temp, Real &energy, Real &press, - Real &cv, Real &bmod, const unsigned long output, - Real *lambda = nullptr) const; + template + PORTABLE_INLINE_FUNCTION void + FillEos(Real &rho, Real &temp, Real &energy, Real &press, Real &cv, Real &bmod, + const unsigned long output, + Indexer_t &&lambda = static_cast(nullptr)) const; SG_PIF_NOWARN + template PORTABLE_INLINE_FUNCTION void - DensityEnergyFromPressureTemperature(const Real press, const Real temp, Real *lambda, - Real &rho, Real &sie) const; + DensityEnergyFromPressureTemperature(const Real press, const Real temp, + Indexer_t &&lambda, Real &rho, Real &sie) const; SG_PIF_NOWARN - PORTABLE_INLINE_FUNCTION void ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, - Real &press, Real &cv, Real &bmod, - Real &dpde, Real &dvdt, - Real *lambda = nullptr) const; + template + PORTABLE_INLINE_FUNCTION void + ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, + Real &bmod, Real &dpde, Real &dvdt, + Indexer_t &&lambda = static_cast(nullptr)) const; // Generic (Scalar) using EosBase::is_raw_pointer; @@ -1180,8 +1209,9 @@ inline EOSPAC::EOSPAC(const int matid, bool invert_at_setup, Real insert_data, } SG_PIF_NOWARN +template PORTABLE_INLINE_FUNCTION Real EOSPAC::TemperatureFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda) const { + const Real rho, const Real sie, Indexer_t &&lambda) const { using namespace EospacWrapper; EOS_REAL R[1] = {rho}, E[1] = {sieToSesame(sie)}, T[1], dTdr[1], dTde[1]; EOS_INTEGER nxypairs = 1; @@ -1191,9 +1221,9 @@ PORTABLE_INLINE_FUNCTION Real EOSPAC::TemperatureFromDensityInternalEnergy( } SG_PIF_NOWARN -PORTABLE_INLINE_FUNCTION Real EOSPAC::PressureFromDensityTemperature(const Real rho, - const Real temp, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real EOSPAC::PressureFromDensityTemperature( + const Real rho, const Real temp, Indexer_t &&lambda) const { using namespace EospacWrapper; EOS_REAL R[1] = {rho}, P[1], T[1] = {temperatureToSesame(temp)}, dPdr[1], dPdT[1]; EOS_INTEGER nxypairs = 1; @@ -1203,17 +1233,18 @@ PORTABLE_INLINE_FUNCTION Real EOSPAC::PressureFromDensityTemperature(const Real } SG_PIF_NOWARN +template PORTABLE_INLINE_FUNCTION Real EOSPAC::EntropyFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda) const { + const Real rho, const Real temperature, Indexer_t &&lambda) const { EntropyIsNotEnabled("EOSPAC"); return 1.0; } SG_PIF_NOWARN -PORTABLE_INLINE_FUNCTION void EOSPAC::FillEos(Real &rho, Real &temp, Real &sie, - Real &press, Real &cv, Real &bmod, - const unsigned long output, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION void +EOSPAC::FillEos(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, Real &bmod, + const unsigned long output, Indexer_t &&lambda) const { using namespace EospacWrapper; EOS_REAL R[1] = {rho}, T[1] = {temperatureToSesame(temp)}; EOS_REAL E[1] = {sieToSesame(sie)}, P[1] = {pressureToSesame(press)}; @@ -1294,8 +1325,9 @@ PORTABLE_INLINE_FUNCTION void EOSPAC::FillEos(Real &rho, Real &temp, Real &sie, } SG_PIF_NOWARN +template PORTABLE_INLINE_FUNCTION Real EOSPAC::InternalEnergyFromDensityTemperature( - const Real rho, const Real temp, Real *lambda) const { + const Real rho, const Real temp, Indexer_t &&lambda) const { using namespace EospacWrapper; Real RHO = rho, TEMP = temp, sie, press, cv, bmod; const unsigned long output = thermalqs::specific_internal_energy; @@ -1303,8 +1335,9 @@ PORTABLE_INLINE_FUNCTION Real EOSPAC::InternalEnergyFromDensityTemperature( return sie; } SG_PIF_NOWARN +template PORTABLE_INLINE_FUNCTION Real EOSPAC::BulkModulusFromDensityTemperature( - const Real rho, const Real temp, Real *lambda) const { + const Real rho, const Real temp, Indexer_t &&lambda) const { using namespace EospacWrapper; Real RHO = rho, TEMP = temp, sie, press, cv, bmod; const unsigned long output = thermalqs::bulk_modulus; @@ -1312,8 +1345,9 @@ PORTABLE_INLINE_FUNCTION Real EOSPAC::BulkModulusFromDensityTemperature( return bmod; } SG_PIF_NOWARN +template PORTABLE_INLINE_FUNCTION Real EOSPAC::SpecificHeatFromDensityTemperature( - const Real rho, const Real temp, Real *lambda) const { + const Real rho, const Real temp, Indexer_t &&lambda) const { using namespace EospacWrapper; Real RHO = rho, TEMP = temp, sie, press, cv, bmod; const unsigned long output = thermalqs::specific_heat; @@ -1321,8 +1355,9 @@ PORTABLE_INLINE_FUNCTION Real EOSPAC::SpecificHeatFromDensityTemperature( return cv; } SG_PIF_NOWARN +template PORTABLE_INLINE_FUNCTION Real EOSPAC::PressureFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda) const { + const Real rho, const Real sie, Indexer_t &&lambda) const { using namespace EospacWrapper; EOS_INTEGER options[]{EOS_Y_CONVERT, EOS_F_CONVERT}; EOS_REAL values[]{sieFromSesame(1.0), pressureFromSesame(1.0)}; @@ -1336,8 +1371,9 @@ PORTABLE_INLINE_FUNCTION Real EOSPAC::PressureFromDensityInternalEnergy( return Real(P[0]); } SG_PIF_NOWARN -PORTABLE_INLINE_FUNCTION Real EOSPAC::MinInternalEnergyFromDensity(const Real rho, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real +EOSPAC::MinInternalEnergyFromDensity(const Real rho, Indexer_t &&lambda) const { using namespace EospacWrapper; EOS_INTEGER options[]{EOS_F_CONVERT}; EOS_REAL values[]{sieFromSesame(1.0)}; @@ -1351,30 +1387,34 @@ PORTABLE_INLINE_FUNCTION Real EOSPAC::MinInternalEnergyFromDensity(const Real rh return Real(S[0]); } SG_PIF_NOWARN +template PORTABLE_INLINE_FUNCTION Real EOSPAC::EntropyFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda) const { + const Real rho, const Real sie, Indexer_t &&lambda) const { using namespace EospacWrapper; const Real temp = TemperatureFromDensityInternalEnergy(rho, sie, lambda); return EntropyFromDensityTemperature(rho, temp, lambda); } SG_PIF_NOWARN +template PORTABLE_INLINE_FUNCTION Real EOSPAC::SpecificHeatFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda) const { + const Real rho, const Real sie, Indexer_t &&lambda) const { using namespace EospacWrapper; Real temp = TemperatureFromDensityInternalEnergy(rho, sie, lambda); return SpecificHeatFromDensityTemperature(rho, temp, lambda); } SG_PIF_NOWARN +template PORTABLE_INLINE_FUNCTION Real EOSPAC::BulkModulusFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda) const { + const Real rho, const Real sie, Indexer_t &&lambda) const { using namespace EospacWrapper; Real temp = TemperatureFromDensityInternalEnergy(rho, sie, lambda); return BulkModulusFromDensityTemperature(rho, temp, lambda); } SG_PIF_NOWARN +template PORTABLE_INLINE_FUNCTION Real EOSPAC::GruneisenParamFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda) const { + const Real rho, const Real temperature, Indexer_t &&lambda) const { using namespace EospacWrapper; EOS_REAL R[1] = {rho}, T[1] = {temperatureToSesame(temperature)}; EOS_REAL E[1], P[1], dx[1], dy[1]; @@ -1390,16 +1430,17 @@ PORTABLE_INLINE_FUNCTION Real EOSPAC::GruneisenParamFromDensityTemperature( return robust::ratio(pressureFromSesame(sieToSesame(DPDE)), rho); } SG_PIF_NOWARN +template PORTABLE_INLINE_FUNCTION Real EOSPAC::GruneisenParamFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda) const { + const Real rho, const Real sie, Indexer_t &&lambda) const { Real temperature = TemperatureFromDensityInternalEnergy(rho, sie, lambda); return GruneisenParamFromDensityTemperature(rho, temperature, lambda); } SG_PIF_NOWARN -PORTABLE_INLINE_FUNCTION void -EOSPAC::DensityEnergyFromPressureTemperature(const Real press, const Real temp, - Real *lambda, Real &rho, Real &sie) const { +template +PORTABLE_INLINE_FUNCTION void EOSPAC::DensityEnergyFromPressureTemperature( + const Real press, const Real temp, Indexer_t &&lambda, Real &rho, Real &sie) const { using namespace EospacWrapper; EOS_REAL P[1] = {pressureToSesame(press)}; EOS_REAL T[1] = {temperatureToSesame(temp)}; @@ -1417,9 +1458,11 @@ EOSPAC::DensityEnergyFromPressureTemperature(const Real press, const Real temp, } SG_PIF_NOWARN +template PORTABLE_INLINE_FUNCTION void EOSPAC::ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, - Real &bmod, Real &dpde, Real &dvdt, Real *lambda) const { + Real &bmod, Real &dpde, Real &dvdt, + Indexer_t &&lambda) const { using namespace EospacWrapper; rho = rho_ref_; temp = temp_ref_; diff --git a/singularity-eos/eos/eos_gruneisen.hpp b/singularity-eos/eos/eos_gruneisen.hpp index 1cbdc90061..1e8254614a 100644 --- a/singularity-eos/eos/eos_gruneisen.hpp +++ b/singularity-eos/eos/eos_gruneisen.hpp @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// © 2021-2023. Triad National Security, LLC. All rights reserved. This +// © 2021-2024. Triad National Security, LLC. All rights reserved. This // program was produced under U.S. Government contract 89233218CNA000001 // for Los Alamos National Laboratory (LANL), which is operated by Triad // National Security, LLC for the U.S. Department of Energy/National @@ -64,51 +64,79 @@ class Gruneisen : public EosBase { static PORTABLE_INLINE_FUNCTION Real ComputeRhoMax(const Real s1, const Real s2, const Real s3, const Real rho0); Gruneisen GetOnDevice() { return *this; } + template PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { return _T0 + sie / _Cv; } + template PORTABLE_INLINE_FUNCTION Real InternalEnergyFromDensityTemperature( - const Real rho, const Real temp, Real *lambda = nullptr) const { + const Real rho, const Real temp, + Indexer_t &&lambda = static_cast(nullptr)) const { return _Cv * (temp - _T0); } - PORTABLE_INLINE_FUNCTION Real PressureFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const; + template + PORTABLE_INLINE_FUNCTION Real + PressureFromDensityTemperature(const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const; + template PORTABLE_INLINE_FUNCTION Real PressureFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const; + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real MinInternalEnergyFromDensity( + const Real rho, Indexer_t &&lambda = static_cast(nullptr)) const; + template PORTABLE_INLINE_FUNCTION Real - MinInternalEnergyFromDensity(const Real rho, Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION Real EntropyFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const; + EntropyFromDensityTemperature(const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const; + template PORTABLE_INLINE_FUNCTION Real EntropyFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const; + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityTemperature( - const Real rho, const Real temperatummmmmmre, Real *lambda = nullptr) const { + const Real rho, const Real temperatummmmmmre, + Indexer_t &&lambda = static_cast(nullptr)) const { return _Cv; } + template PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { return _Cv; } + template PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const; + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const; + template PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const; + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { return Gamma(std::min(rho, _rho_max)); } + template PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { return Gamma(std::min(rho, _rho_max)); } - PORTABLE_INLINE_FUNCTION void FillEos(Real &rho, Real &temp, Real &energy, Real &press, - Real &cv, Real &bmod, const unsigned long output, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - void ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, - Real &bmod, Real &dpde, Real &dvdt, - Real *lambda = nullptr) const; + template + PORTABLE_INLINE_FUNCTION void + FillEos(Real &rho, Real &temp, Real &energy, Real &press, Real &cv, Real &bmod, + const unsigned long output, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION void + ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, + Real &bmod, Real &dpde, Real &dvdt, + Indexer_t &&lambda = static_cast(nullptr)) const; // Generic functions provided by the base class. These contain e.g. the vector // overloads that use the scalar versions declared here SG_ADD_BASE_CLASS_USINGS(Gruneisen) @@ -125,9 +153,10 @@ class Gruneisen : public EosBase { "rho_max:%e\n", s1, _C0, _s1, _s2, _s3, _G0, _b, _rho0, _T0, _P0, _Cv, _rho_max); } + template PORTABLE_INLINE_FUNCTION void - DensityEnergyFromPressureTemperature(const Real press, const Real temp, Real *lambda, - Real &rho, Real &sie) const; + DensityEnergyFromPressureTemperature(const Real press, const Real temp, + Indexer_t &&lambda, Real &rho, Real &sie) const; inline void Finalize() {} static std::string EosType() { return std::string("Gruneisen"); } static std::string EosPyType() { return EosType(); } @@ -297,8 +326,9 @@ PORTABLE_INLINE_FUNCTION Real Gruneisen::dPres_drho_e(const Real rho_in, } } +template PORTABLE_INLINE_FUNCTION Real Gruneisen::PressureFromDensityInternalEnergy( - const Real rho_in, const Real sie, Real *lambda) const { + const Real rho_in, const Real sie, Indexer_t &&lambda) const { using namespace math_utils; const Real rho = std::min(rho_in, _rho_max); Real P_H; @@ -315,20 +345,23 @@ PORTABLE_INLINE_FUNCTION Real Gruneisen::PressureFromDensityInternalEnergy( } return P_H + Gamma(rho) * rho * (sie - E_H); } +template PORTABLE_INLINE_FUNCTION Real -Gruneisen::MinInternalEnergyFromDensity(const Real rho_in, Real *lambda) const { +Gruneisen::MinInternalEnergyFromDensity(const Real rho_in, Indexer_t &&lambda) const { const Real rho = std::min(rho_in, _rho_max); MinInternalEnergyIsNotEnabled("Gruneisen"); return 0.0; } +template PORTABLE_INLINE_FUNCTION Real Gruneisen::EntropyFromDensityInternalEnergy( - const Real rho_in, const Real sie, Real *lambda) const { + const Real rho_in, const Real sie, Indexer_t &&lambda) const { const Real rho = std::min(rho_in, _rho_max); EntropyIsNotEnabled("Gruneisen"); return 1.0; } +template PORTABLE_INLINE_FUNCTION Real Gruneisen::BulkModulusFromDensityInternalEnergy( - const Real rho_in, const Real sie, Real *lambda) const { + const Real rho_in, const Real sie, Indexer_t &&lambda) const { using namespace gruneisen_utils; const Real rho = std::min(rho_in, _rho_max); // The if statement exists here to avoid the divide by zero @@ -343,26 +376,30 @@ PORTABLE_INLINE_FUNCTION Real Gruneisen::BulkModulusFromDensityInternalEnergy( } } // Below are "unimplemented" routines +template PORTABLE_INLINE_FUNCTION Real Gruneisen::PressureFromDensityTemperature( - const Real rho_in, const Real temp, Real *lambda) const { + const Real rho_in, const Real temp, Indexer_t &&lambda) const { const Real rho = std::min(rho_in, _rho_max); return PressureFromDensityInternalEnergy( rho, InternalEnergyFromDensityTemperature(rho, temp)); } +template PORTABLE_INLINE_FUNCTION Real Gruneisen::EntropyFromDensityTemperature( - const Real rho_in, const Real temp, Real *lambda) const { + const Real rho_in, const Real temp, Indexer_t &&lambda) const { const Real rho = std::min(rho_in, _rho_max); const Real sie = InternalEnergyFromDensityTemperature(rho, temp); return EntropyFromDensityInternalEnergy(rho, sie); } +template PORTABLE_INLINE_FUNCTION Real Gruneisen::BulkModulusFromDensityTemperature( - const Real rho_in, const Real temp, Real *lambda) const { + const Real rho_in, const Real temp, Indexer_t &&lambda) const { const Real rho = std::min(rho_in, _rho_max); return BulkModulusFromDensityInternalEnergy( rho, InternalEnergyFromDensityTemperature(rho, temp)); } +template PORTABLE_INLINE_FUNCTION void Gruneisen::DensityEnergyFromPressureTemperature( - const Real press, const Real temp, Real *lambda, Real &rho, Real &sie) const { + const Real press, const Real temp, Indexer_t &&lambda, Real &rho, Real &sie) const { sie = _Cv * (temp - _T0); // We have a branch at rho0, so we need to decide, based on our pressure, whether we // should be above or below rho0 @@ -383,10 +420,10 @@ PORTABLE_INLINE_FUNCTION void Gruneisen::DensityEnergyFromPressureTemperature( } } } -PORTABLE_INLINE_FUNCTION void Gruneisen::FillEos(Real &rho_in, Real &temp, Real &sie, - Real &press, Real &cv, Real &bmod, - const unsigned long output, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION void +Gruneisen::FillEos(Real &rho_in, Real &temp, Real &sie, Real &press, Real &cv, Real &bmod, + const unsigned long output, Indexer_t &&lambda) const { // The following could be sped up with work! const unsigned long input = ~output; if (thermalqs::temperature & input && thermalqs::pressure & input) { @@ -408,10 +445,11 @@ PORTABLE_INLINE_FUNCTION void Gruneisen::FillEos(Real &rho_in, Real &temp, Real } // TODO(JMM): pre-cache these rather than recomputing them each time -PORTABLE_INLINE_FUNCTION -void Gruneisen::ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, - Real &cv, Real &bmod, Real &dpde, Real &dvdt, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION void +Gruneisen::ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, + Real &bmod, Real &dpde, Real &dvdt, + Indexer_t &&lambda) const { rho = _rho0; temp = _T0; sie = 0; diff --git a/singularity-eos/eos/eos_helmholtz.hpp b/singularity-eos/eos/eos_helmholtz.hpp index 957cdc2854..3dc5b07d41 100644 --- a/singularity-eos/eos/eos_helmholtz.hpp +++ b/singularity-eos/eos/eos_helmholtz.hpp @@ -6,7 +6,7 @@ // Original work is open-sourced under the CC-By license // https://creativecommons.org/licenses/by/4.0/ //------------------------------------------------------------------------------ -// © 2023. Triad National Security, LLC. All rights reserved. This +// © 2023-2024. Triad National Security, LLC. All rights reserved. This // program was produced under U.S. Government contract 89233218CNA000001 // for Los Alamos National Laboratory (LANL), which is operated by Triad // National Security, LLC for the U.S. Department of Energy/National @@ -460,32 +460,40 @@ class Helmholtz : public EosBase { dxnida = -xni * ytot; } + template PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { Real rl = rho; Real el = sie; Real temperature, p, cv, bmod; FillEos(rl, temperature, el, p, cv, bmod, thermalqs::temperature, lambda); return temperature; } + template PORTABLE_INLINE_FUNCTION Real InternalEnergyFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { Real rl = rho; Real tl = temperature; Real sie, p, cv, bmod; FillEos(rl, tl, sie, p, cv, bmod, thermalqs::specific_internal_energy, lambda); return sie; } + template PORTABLE_INLINE_FUNCTION Real PressureFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { Real rl = rho; Real tl = temperature; Real sie, p, cv, bmod; FillEos(rl, tl, sie, p, cv, bmod, thermalqs::pressure, lambda); return p; } + template PORTABLE_INLINE_FUNCTION Real PressureFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { Real rl = rho; Real el = sie; Real temperature, p, cv, bmod; @@ -493,35 +501,44 @@ class Helmholtz : public EosBase { thermalqs::pressure | thermalqs::temperature, lambda); return p; } - PORTABLE_INLINE_FUNCTION Real - MinInternalEnergyFromDensity(const Real rho, Real *lambda = nullptr) const { + template + PORTABLE_INLINE_FUNCTION Real MinInternalEnergyFromDensity( + const Real rho, Indexer_t &&lambda = static_cast(nullptr)) const { MinInternalEnergyIsNotEnabled("Helmholtz"); return 0.0; } - PORTABLE_INLINE_FUNCTION Real EntropyFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + template + PORTABLE_INLINE_FUNCTION Real + EntropyFromDensityTemperature(const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { Real p[NDERIV], e[NDERIV], s[NDERIV], etaele[NDERIV], nep[NDERIV]; GetFromDensityTemperature_(rho, temperature, lambda, p, e, s, etaele, nep); return s[HelmUtils::VAL]; } + template PORTABLE_INLINE_FUNCTION Real EntropyFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { Real p[NDERIV], e[NDERIV], s[NDERIV], etaele[NDERIV], nep[NDERIV]; GetFromDensityInternalEnergy_(rho, sie, lambda, p, e, s, etaele, nep); return s[HelmUtils::VAL]; } + template PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { Real rl = rho; Real tl = temperature; Real sie, p, cv, bmod; FillEos(rl, tl, sie, p, cv, bmod, thermalqs::specific_heat, lambda); return cv; } + template PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { Real rl = rho; Real el = sie; Real temperature, p, cv, bmod; @@ -529,16 +546,20 @@ class Helmholtz : public EosBase { thermalqs::specific_heat | thermalqs::temperature, lambda); return cv; } + template PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { Real rl = rho; Real tl = temperature; Real sie, p, cv, bmod; FillEos(rl, tl, sie, p, cv, bmod, thermalqs::bulk_modulus, lambda); return bmod; } + template PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { Real rl = rho; Real el = sie; Real temperature, p, cv, bmod; @@ -547,16 +568,20 @@ class Helmholtz : public EosBase { return bmod; } + template PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { using namespace HelmUtils; Real p[NDERIV], e[NDERIV], s[NDERIV], etaele[NDERIV], nep[NDERIV]; GetFromDensityTemperature_(rho, temperature, lambda, p, e, s, etaele, nep); Real gamma3 = ComputeGamma3_(rho, temperature, p, e); return gamma3 - 1.0; } + template PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { using namespace HelmUtils; Real p[NDERIV], e[NDERIV], s[NDERIV], etaele[NDERIV], nep[NDERIV]; Real abar = lambda[Lambda::Abar]; @@ -571,21 +596,25 @@ class Helmholtz : public EosBase { return gamma3 - 1.0; } - PORTABLE_INLINE_FUNCTION - void FillEos(Real &rho, Real &temp, Real &energy, Real &press, Real &cv, Real &bmod, - const unsigned long output, Real *lambda = nullptr) const; + template + PORTABLE_INLINE_FUNCTION void + FillEos(Real &rho, Real &temp, Real &energy, Real &press, Real &cv, Real &bmod, + const unsigned long output, + Indexer_t &&lambda = static_cast(nullptr)) const; - PORTABLE_INLINE_FUNCTION - void ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, - Real &bmod, Real &dpde, Real &dvdt, - Real *lambda = nullptr) const { + template + PORTABLE_INLINE_FUNCTION void + ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, + Real &bmod, Real &dpde, Real &dvdt, + Indexer_t &&lambda = static_cast(nullptr)) const { // JMM: I'm not sure what to put here or if it matters. Some // reference state, maybe stellar denity, would be appropriate. PORTABLE_ALWAYS_ABORT("Stub"); } + template PORTABLE_INLINE_FUNCTION void - DensityEnergyFromPressureTemperature(const Real press, const Real temp, Real *lambda, - Real &rho, Real &sie) const { + DensityEnergyFromPressureTemperature(const Real press, const Real temp, + Indexer_t &&lambda, Real &rho, Real &sie) const { // This is only used for mixed cell closures. Stubbing it out for now. PORTABLE_ALWAYS_ABORT("Stub"); } @@ -631,10 +660,11 @@ class Helmholtz : public EosBase { return std::log10((2.0 / 3.0) * robust::ratio(e * rho, ni + ne) * ions_.KBi); } - PORTABLE_INLINE_FUNCTION - void GetFromDensityTemperature_(const Real rho, const Real temperature, Real *lambda, - Real p[NDERIV], Real e[NDERIV], Real s[NDERIV], - Real etaele[NDERIV], Real nep[NDERIV]) const { + template + PORTABLE_INLINE_FUNCTION void + GetFromDensityTemperature_(const Real rho, const Real temperature, Indexer_t &&lambda, + Real p[NDERIV], Real e[NDERIV], Real s[NDERIV], + Real etaele[NDERIV], Real nep[NDERIV]) const { Real abar = lambda[Lambda::Abar]; Real zbar = lambda[Lambda::Zbar]; Real lT = std::log10(temperature); @@ -645,10 +675,11 @@ class Helmholtz : public EosBase { p, e, s, etaele, nep); } - PORTABLE_INLINE_FUNCTION - void GetFromDensityInternalEnergy_(const Real rho, const Real sie, Real *lambda, - Real p[NDERIV], Real e[NDERIV], Real s[NDERIV], - Real etaele[NDERIV], Real nep[NDERIV]) const { + template + PORTABLE_INLINE_FUNCTION void + GetFromDensityInternalEnergy_(const Real rho, const Real sie, Indexer_t &&lambda, + Real p[NDERIV], Real e[NDERIV], Real s[NDERIV], + Real etaele[NDERIV], Real nep[NDERIV]) const { Real abar = lambda[Lambda::Abar]; Real zbar = lambda[Lambda::Zbar]; Real ytot, ye, ywot, De, lDe; @@ -667,10 +698,12 @@ class Helmholtz : public EosBase { // TODO(JMM): Decide which of the quantities below to keep const bool only_e = false) const; - PORTABLE_INLINE_FUNCTION - Real lTFromRhoSie_(const Real rho, const Real e, const Real abar, const Real zbar, - const Real ye, const Real ytot, const Real ywot, const Real De, - const Real lDe, Real *lambda) const; + template + PORTABLE_INLINE_FUNCTION Real lTFromRhoSie_(const Real rho, const Real e, + const Real abar, const Real zbar, + const Real ye, const Real ytot, + const Real ywot, const Real De, + const Real lDe, Indexer_t &&lambda) const; static constexpr Real ROOT_THRESH = 1e-14; static constexpr Real HELM_EOS_EPS = 1e-10; @@ -681,9 +714,10 @@ class Helmholtz : public EosBase { HelmElectrons electrons_; }; -PORTABLE_INLINE_FUNCTION -void Helmholtz::FillEos(Real &rho, Real &temp, Real &energy, Real &press, Real &cv, - Real &bmod, const unsigned long output, Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION void +Helmholtz::FillEos(Real &rho, Real &temp, Real &energy, Real &press, Real &cv, Real &bmod, + const unsigned long output, Indexer_t &&lambda) const { using namespace HelmUtils; bool need_temp = (output & thermalqs::temperature); bool need_sie = (output & thermalqs::specific_internal_energy); @@ -727,11 +761,13 @@ void Helmholtz::FillEos(Real &rho, Real &temp, Real &energy, Real &press, Real & } } -PORTABLE_INLINE_FUNCTION -Real Helmholtz::lTFromRhoSie_(const Real rho, const Real e, const Real abar, - const Real zbar, const Real ye, const Real ytot, - const Real ywot, const Real De, const Real lDe, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real Helmholtz::lTFromRhoSie_(const Real rho, const Real e, + const Real abar, const Real zbar, + const Real ye, const Real ytot, + const Real ywot, const Real De, + const Real lDe, + Indexer_t &&lambda) const { using namespace HelmUtils; const Real abari = robust::ratio(1.0, abar); const Real ni = abari * rho * ions_.NA; diff --git a/singularity-eos/eos/eos_ideal.hpp b/singularity-eos/eos/eos_ideal.hpp index dc52e84fa7..489c3a6553 100644 --- a/singularity-eos/eos/eos_ideal.hpp +++ b/singularity-eos/eos/eos_ideal.hpp @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// © 2021-2023. Triad National Security, LLC. All rights reserved. This +// © 2021-2024. Triad National Security, LLC. All rights reserved. This // program was produced under U.S. Government contract 89233218CNA000001 // for Los Alamos National Laboratory (LANL), which is operated by Triad // National Security, LLC for the U.S. Department of Energy/National @@ -52,8 +52,10 @@ class IdealGas : public EosBase { } IdealGas GetOnDevice() { return *this; } + template PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { return MYMAX(0.0, sie / _Cv); } PORTABLE_INLINE_FUNCTION void checkParams() const { @@ -66,64 +68,90 @@ class IdealGas : public EosBase { PORTABLE_ALWAYS_REQUIRE(_EntropyRho0 >= 0, "Entropy reference density must be positive"); } + template PORTABLE_INLINE_FUNCTION Real InternalEnergyFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { return MYMAX(0.0, _Cv * temperature); } + template PORTABLE_INLINE_FUNCTION Real PressureFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { return MYMAX(0.0, _gm1 * rho * _Cv * temperature); } + template PORTABLE_INLINE_FUNCTION Real PressureFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { return MYMAX(0.0, _gm1 * rho * sie); } - PORTABLE_INLINE_FUNCTION Real - MinInternalEnergyFromDensity(const Real rho, Real *lambda = nullptr) const { + template + PORTABLE_INLINE_FUNCTION Real MinInternalEnergyFromDensity( + const Real rho, Indexer_t &&lambda = static_cast(nullptr)) const { return 0.0; }; - PORTABLE_INLINE_FUNCTION Real EntropyFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + template + PORTABLE_INLINE_FUNCTION Real + EntropyFromDensityTemperature(const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { return _Cv * log(robust::ratio(temperature, _EntropyT0)) + _gm1 * _Cv * log(robust::ratio(_EntropyRho0, rho)); } + template PORTABLE_INLINE_FUNCTION Real EntropyFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { const Real temp = TemperatureFromDensityInternalEnergy(rho, sie, lambda); return EntropyFromDensityTemperature(rho, temp, lambda); } + template PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { return _Cv; } + template PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { return _Cv; } + template PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { return MYMAX(0.0, (_gm1 + 1) * _gm1 * rho * _Cv * temperature); } + template PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { return MYMAX(0.0, (_gm1 + 1) * _gm1 * rho * sie); } + template PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { return _gm1; } + template PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { return _gm1; } - PORTABLE_INLINE_FUNCTION void FillEos(Real &rho, Real &temp, Real &energy, Real &press, - Real &cv, Real &bmod, const unsigned long output, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - void ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, - Real &bmod, Real &dpde, Real &dvdt, - Real *lambda = nullptr) const { + template + PORTABLE_INLINE_FUNCTION void + FillEos(Real &rho, Real &temp, Real &energy, Real &press, Real &cv, Real &bmod, + const unsigned long output, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION void + ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, + Real &bmod, Real &dpde, Real &dvdt, + Indexer_t &&lambda = static_cast(nullptr)) const { // use STP: 1 atmosphere, room temperature rho = _rho0; temp = _T0; @@ -147,9 +175,10 @@ class IdealGas : public EosBase { PORTABLE_INLINE_FUNCTION void PrintParams() const { printf("Ideal Gas Parameters:\nGamma = %g\nCv = %g\n", _gm1 + 1.0, _Cv); } + template PORTABLE_INLINE_FUNCTION void - DensityEnergyFromPressureTemperature(const Real press, const Real temp, Real *lambda, - Real &rho, Real &sie) const { + DensityEnergyFromPressureTemperature(const Real press, const Real temp, + Indexer_t &&lambda, Real &rho, Real &sie) const { sie = MYMAX(0.0, _Cv * temp); rho = MYMAX(0.0, press / (_gm1 * sie)); } @@ -170,9 +199,10 @@ class IdealGas : public EosBase { Real _EntropyT0, _EntropyRho0; }; -PORTABLE_INLINE_FUNCTION -void IdealGas::FillEos(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, - Real &bmod, const unsigned long output, Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION void +IdealGas::FillEos(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, Real &bmod, + const unsigned long output, Indexer_t &&lambda) const { if (output & thermalqs::density && output & thermalqs::specific_internal_energy) { if (output & thermalqs::pressure || output & thermalqs::temperature) { UNDEFINED_ERROR; diff --git a/singularity-eos/eos/eos_jwl.hpp b/singularity-eos/eos/eos_jwl.hpp index d670a4e279..6cf06ad947 100644 --- a/singularity-eos/eos/eos_jwl.hpp +++ b/singularity-eos/eos/eos_jwl.hpp @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// © 2021-2023. Triad National Security, LLC. All rights reserved. This +// © 2021-2024. Triad National Security, LLC. All rights reserved. This // program was produced under U.S. Government contract 89233218CNA000001 // for Los Alamos National Laboratory (LANL), which is operated by Triad // National Security, LLC for the U.S. Department of Energy/National @@ -50,44 +50,72 @@ class JWL : public EosBase { assert(Cv > 0.0); } JWL GetOnDevice() { return *this; } + template PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const; + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template PORTABLE_INLINE_FUNCTION Real InternalEnergyFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION Real PressureFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const; + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real + PressureFromDensityTemperature(const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const; + template PORTABLE_INLINE_FUNCTION Real PressureFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const; + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real MinInternalEnergyFromDensity( + const Real rho, Indexer_t &&lambda = static_cast(nullptr)) const; + template PORTABLE_INLINE_FUNCTION Real - MinInternalEnergyFromDensity(const Real rho, Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION Real EntropyFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const; + EntropyFromDensityTemperature(const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const; + template PORTABLE_INLINE_FUNCTION Real EntropyFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const; + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const; + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const; + template PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const; + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const; + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const; + template PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const; + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const; + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const; + template PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION void FillEos(Real &rho, Real &temp, Real &energy, Real &press, - Real &cv, Real &bmod, const unsigned long output, - Real *lambda = nullptr) const; + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION void + FillEos(Real &rho, Real &temp, Real &energy, Real &press, Real &cv, Real &bmod, + const unsigned long output, + Indexer_t &&lambda = static_cast(nullptr)) const; // Generic functions provided by the base class. These contain e.g. the vector // overloads that use the scalar versions declared here SG_ADD_BASE_CLASS_USINGS(JWL) PORTABLE_INLINE_FUNCTION int nlambda() const noexcept { return 0; } - PORTABLE_INLINE_FUNCTION - void ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, - Real &bmod, Real &dpde, Real &dvdt, - Real *lambda = nullptr) const; + template + PORTABLE_INLINE_FUNCTION void + ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, + Real &bmod, Real &dpde, Real &dvdt, + Indexer_t &&lambda = static_cast(nullptr)) const; static constexpr unsigned long PreferredInput() { return _preferred_input; } static inline unsigned long scratch_size(std::string method, unsigned int nelements) { return 0; @@ -98,9 +126,10 @@ class JWL : public EosBase { printf("%sA:%e B:%e R1: %e\nR2:%e w:%e rho0:%e\nCv:%e\n", s1, _A, _B, _R1, _R2, _w, _rho0, _Cv); } + template PORTABLE_INLINE_FUNCTION void - DensityEnergyFromPressureTemperature(const Real press, const Real temp, Real *lambda, - Real &rho, Real &sie) const; + DensityEnergyFromPressureTemperature(const Real press, const Real temp, + Indexer_t &&lambda, Real &rho, Real &sie) const; inline void Finalize() {} static std::string EosType() { return std::string("JWL"); } static std::string EosPyType() { return EosType(); } @@ -122,36 +151,41 @@ PORTABLE_FORCEINLINE_FUNCTION Real JWL::ReferenceEnergy(const Real rho) const { const Real x = robust::ratio(_rho0, rho); return _c1 * robust::safe_arg_exp(-_R1 * x) + _c2 * robust::safe_arg_exp(-_R2 * x); } +template PORTABLE_INLINE_FUNCTION Real JWL::InternalEnergyFromDensityTemperature( - const Real rho, const Real temp, Real *lambda) const { + const Real rho, const Real temp, Indexer_t &&lambda) const { return ReferenceEnergy(rho) + _Cv * temp; } -PORTABLE_INLINE_FUNCTION Real JWL::PressureFromDensityInternalEnergy(const Real rho, - const Real sie, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real JWL::PressureFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda) const { return ReferencePressure(rho) + _w * rho * (sie - ReferenceEnergy(rho)); } -PORTABLE_INLINE_FUNCTION Real JWL::MinInternalEnergyFromDensity(const Real rho, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real +JWL::MinInternalEnergyFromDensity(const Real rho, Indexer_t &&lambda) const { MinInternalEnergyIsNotEnabled("JWL"); return 0.0; } -PORTABLE_INLINE_FUNCTION Real JWL::EntropyFromDensityInternalEnergy(const Real rho, - const Real sie, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real JWL::EntropyFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda) const { EntropyIsNotEnabled("JWL"); return 1.0; } +template PORTABLE_INLINE_FUNCTION Real JWL::TemperatureFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda) const { + const Real rho, const Real sie, Indexer_t &&lambda) const { return robust::ratio((sie - ReferenceEnergy(rho)), _Cv); } +template PORTABLE_INLINE_FUNCTION Real JWL::SpecificHeatFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda) const { + const Real rho, const Real sie, Indexer_t &&lambda) const { return _Cv; } +template PORTABLE_INLINE_FUNCTION Real JWL::BulkModulusFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda) const { + const Real rho, const Real sie, Indexer_t &&lambda) const { const Real x = robust::ratio(_rho0, rho); // return // (_w+1)*(PressureFromDensityInternalEnergy(rho,sie)-ReferencePressure(rho))+x*(_A*_R1*std::exp(-_R1*x)+_B*_R2*std::exp(-_R2*x)); @@ -159,43 +193,44 @@ PORTABLE_INLINE_FUNCTION Real JWL::BulkModulusFromDensityInternalEnergy( x * (_A * _R1 * robust::safe_arg_exp(-_R1 * x) + _B * _R2 * robust::safe_arg_exp(-_R2 * x)); } -PORTABLE_INLINE_FUNCTION -Real JWL::GruneisenParamFromDensityInternalEnergy(const Real rho, const Real sie, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real JWL::GruneisenParamFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda) const { return _w; } // Below are "unimplemented" routines -PORTABLE_INLINE_FUNCTION Real JWL::PressureFromDensityTemperature(const Real rho, - const Real temp, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real JWL::PressureFromDensityTemperature( + const Real rho, const Real temp, Indexer_t &&lambda) const { return PressureFromDensityInternalEnergy( rho, InternalEnergyFromDensityTemperature(rho, temp)); } -PORTABLE_INLINE_FUNCTION Real JWL::EntropyFromDensityTemperature(const Real rho, - const Real temp, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real JWL::EntropyFromDensityTemperature( + const Real rho, const Real temp, Indexer_t &&lambda) const { EntropyIsNotEnabled("JWL"); return 1.0; } +template PORTABLE_INLINE_FUNCTION Real JWL::SpecificHeatFromDensityTemperature( - const Real rho, const Real temp, Real *lambda) const { + const Real rho, const Real temp, Indexer_t &&lambda) const { return SpecificHeatFromDensityInternalEnergy( rho, InternalEnergyFromDensityTemperature(rho, temp)); } -PORTABLE_INLINE_FUNCTION Real JWL::BulkModulusFromDensityTemperature(const Real rho, - const Real temp, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real JWL::BulkModulusFromDensityTemperature( + const Real rho, const Real temp, Indexer_t &&lambda) const { return BulkModulusFromDensityInternalEnergy( rho, InternalEnergyFromDensityTemperature(rho, temp)); } -PORTABLE_INLINE_FUNCTION -Real JWL::GruneisenParamFromDensityTemperature(const Real rho, const Real temp, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real JWL::GruneisenParamFromDensityTemperature( + const Real rho, const Real temp, Indexer_t &&lambda) const { return _w; } -PORTABLE_INLINE_FUNCTION void -JWL::DensityEnergyFromPressureTemperature(const Real press, const Real temp, Real *lambda, - Real &rho, Real &sie) const { +template +PORTABLE_INLINE_FUNCTION void JWL::DensityEnergyFromPressureTemperature( + const Real press, const Real temp, Indexer_t &&lambda, Real &rho, Real &sie) const { // sie = sie_r + cv*T; Thus sie-sie_r = cv*T // Thus P = P_r +_w*rho*cv*T ==> Invertable? // Turns out not to be exactly invertible @@ -212,10 +247,10 @@ JWL::DensityEnergyFromPressureTemperature(const Real press, const Real temp, Rea } sie = InternalEnergyFromDensityTemperature(rho, temp); } -PORTABLE_INLINE_FUNCTION void JWL::FillEos(Real &rho, Real &temp, Real &sie, Real &press, - Real &cv, Real &bmod, - const unsigned long output, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION void +JWL::FillEos(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, Real &bmod, + const unsigned long output, Indexer_t &&lambda) const { if (output & thermalqs::pressure) press = PressureFromDensityInternalEnergy(rho, sie); if (output & thermalqs::temperature) temp = TemperatureFromDensityInternalEnergy(rho, sie); @@ -228,9 +263,11 @@ PORTABLE_INLINE_FUNCTION void JWL::FillEos(Real &rho, Real &temp, Real &sie, Rea // TODO(JMM): pre-cache these rather than recomputing them each time // TODO: Chad, please decide if STP is actually right here. Should it be // based on the reference energy and pressure instead? -PORTABLE_INLINE_FUNCTION -void JWL::ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, - Real &bmod, Real &dpde, Real &dvdt, Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION void +JWL::ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, + Real &bmod, Real &dpde, Real &dvdt, + Indexer_t &&lambda) const { rho = _rho0; temp = ROOM_TEMPERATURE; sie = InternalEnergyFromDensityTemperature(rho, temp, lambda); diff --git a/singularity-eos/eos/eos_mgusup.hpp b/singularity-eos/eos/eos_mgusup.hpp new file mode 100644 index 0000000000..ab42dbe7c4 --- /dev/null +++ b/singularity-eos/eos/eos_mgusup.hpp @@ -0,0 +1,408 @@ +//------------------------------------------------------------------------------ +// © 2021-2024. Triad National Security, LLC. All rights reserved. This +// program was produced under U.S. Government contract 89233218CNA000001 +// for Los Alamos National Laboratory (LANL), which is operated by Triad +// National Security, LLC for the U.S. Department of Energy/National +// Nuclear Security Administration. All rights in the program are +// reserved by Triad National Security, LLC, and the U.S. Department of +// Energy/National Nuclear Security Administration. The Government is +// granted for itself and others acting on its behalf a nonexclusive, +// paid-up, irrevocable worldwide license in this material to reproduce, +// prepare derivative works, distribute copies to the public, perform +// publicly and display publicly, and to permit others to do so. +//------------------------------------------------------------------------------ + +#ifndef _SINGULARITY_EOS_EOS_MGUSUP_HPP_ +#define _SINGULARITY_EOS_EOS_MGUSUP_HPP_ + +#include +#include + +#include + +#include +#include +#include +#include +#include + +namespace singularity { + +using namespace eos_base; +using namespace robust; + +// COMMENT: This is a complete, thermodynamically consistent Mie-Gruneisen +// EOS based on a linear Us-up Hugoniot, Us=Cs+s*up. +class MGUsup : public EosBase { + public: + MGUsup() = default; + // Constructor + MGUsup(const Real rho0, const Real T0, const Real Cs, const Real s, const Real G0, + const Real Cv0, const Real E0, const Real S0) + : _rho0(rho0), _T0(T0), _Cs(Cs), _s(s), _G0(G0), _Cv0(Cv0), _E0(E0), _S0(S0) { + _CheckMGUsup(); + } + + MGUsup GetOnDevice() { return *this; } + template + PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real InternalEnergyFromDensityTemperature( + const Real rho, const Real temp, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real + PressureFromDensityTemperature(const Real rho, const Real temp, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real PressureFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real MinInternalEnergyFromDensity( + const Real rho, Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real + EntropyFromDensityTemperature(const Real rho, const Real temp, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real EntropyFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityTemperature( + const Real rho, const Real temp, + Indexer_t &&lambda = static_cast(nullptr)) const { + return _Cv0; + } + template + PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { + return _Cv0; + } + // added for testing AEM Dec 2023 + PORTABLE_INLINE_FUNCTION Real HugPressureFromDensity(const Real rho) const; + PORTABLE_INLINE_FUNCTION Real HugInternalEnergyFromDensity(const Real rho) const; + PORTABLE_INLINE_FUNCTION Real HugTemperatureFromDensity(const Real rho) const; + // Thermal Bulk Modulus added AEM Dec 2022 + template + PORTABLE_INLINE_FUNCTION Real TBulkModulusFromDensityTemperature( + const Real rho, const Real temp, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityTemperature( + const Real rho, const Real temp, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + // Thermal expansion coefficient added AEM 2022 + template + PORTABLE_INLINE_FUNCTION Real TExpansionCoeffFromDensityTemperature( + const Real rho, const Real temp, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityTemperature( + const Real rho, const Real temp, + Indexer_t &&lambda = static_cast(nullptr)) const { + return robust::ratio(_G0 * _rho0, rho); + } + template + PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { + return robust::ratio(_G0 * _rho0, rho); + } + template + PORTABLE_INLINE_FUNCTION void + FillEos(Real &rho, Real &temp, Real &energy, Real &press, Real &cv, Real &bmod, + const unsigned long output, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION void + ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, + Real &bmod, Real &dpde, Real &dvdt, + Indexer_t &&lambda = static_cast(nullptr)) const; + // Generic functions provided by the base class. These contain e.g. the vector + // overloads that use the scalar versions declared here + SG_ADD_BASE_CLASS_USINGS(MGUsup) + PORTABLE_INLINE_FUNCTION + int nlambda() const noexcept { return 0; } + static constexpr unsigned long PreferredInput() { return _preferred_input; } + static inline unsigned long scratch_size(std::string method, unsigned int nelements) { + return 0; + } + static inline unsigned long max_scratch_size(unsigned int nelements) { return 0; } + PORTABLE_INLINE_FUNCTION void PrintParams() const { + static constexpr char st[]{"MGUsup Params: "}; + printf("%s rho0:%e T0:%e Cs:%e s:%e\n G0:%e Cv0:%e E0:%e S0:%e\n", st, _rho0, _T0, + _Cs, _s, _G0, _Cv0, _E0, _S0); + printf("\n\n"); + } + // Density/Energy from P/T not unique, if used will give error + template + PORTABLE_INLINE_FUNCTION void + DensityEnergyFromPressureTemperature(const Real press, const Real temp, + Indexer_t &&lambda, Real &rho, Real &sie) const; + inline void Finalize() {} + static std::string EosType() { return std::string("MGUsup"); } + static std::string EosPyType() { return EosType(); } + + private: + static constexpr const unsigned long _preferred_input = + thermalqs::density | thermalqs::specific_internal_energy; + Real _rho0, _T0, _Cs, _s, _G0, _Cv0, _E0, _S0; + void _CheckMGUsup(); +}; + +inline void MGUsup::_CheckMGUsup() { + + if (_rho0 < 0.0) { + PORTABLE_ALWAYS_THROW_OR_ABORT("Required MGUsup model parameter rho0 < 0"); + } + if (_T0 < 0.0) { + PORTABLE_ALWAYS_THROW_OR_ABORT("Required MGUsup model parameter T0 < 0"); + } + if (_Cs < 0.0) { + PORTABLE_ALWAYS_THROW_OR_ABORT("Required MGUsup model parameter Cs < 0"); + } + if (_s < 0.0) { + PORTABLE_ALWAYS_THROW_OR_ABORT("Required MGUsup model parameter s < 0"); + } + if (_G0 < 0.0) { + PORTABLE_ALWAYS_THROW_OR_ABORT("Required MGUsup model parameter G0 < 0"); + } + if (_Cv0 < 0.0) { + PORTABLE_ALWAYS_THROW_OR_ABORT("Required MGUsup model parameter Cv0 < 0"); + } +} + +PORTABLE_INLINE_FUNCTION Real MGUsup::HugPressureFromDensity(Real rho) const { + Real eta = 1.0 - robust::ratio(_rho0, rho); + return _Cs * _Cs * _rho0 * robust::ratio(eta, (1.0 - _s * eta) * (1.0 - _s * eta)); +} +PORTABLE_INLINE_FUNCTION Real MGUsup::HugInternalEnergyFromDensity(Real rho) const { + Real eta = 1.0 - robust::ratio(_rho0, rho); + return _E0 + robust::ratio(eta, 2.0 * _rho0) * HugPressureFromDensity(rho); +} +PORTABLE_INLINE_FUNCTION Real MGUsup::HugTemperatureFromDensity(Real rho) const { + int sumkmax = 20; + Real cutoff = 1.e-16; + Real eta = 1.0 - robust::ratio(_rho0, rho); + Real f1 = 1.0 - _s * eta; + if (f1 <= 0.0) { + PORTABLE_ALWAYS_THROW_OR_ABORT("MGUsup model parameters s and rho0 together with rho " + "give a negative argument for a logarithm."); + } + Real G0os = robust::ratio(_G0, _s); + // sk, lk, mk, sum, and enough values may change in the loop + Real sk = -_G0 * eta; + Real lk = _G0; + Real mk = 0.0; + Real sum = sk; + int enough = 0; + Real temp; + Real pf = _Cs * _Cs / (2.0 * _Cv0 * _s * _s); + if (eta * eta < 1.e-8) { + temp = _T0 * exp(_G0 * eta) + + pf * (2.0 * std::log(f1) - _s * eta / (f1 * f1) * (3.0 * _s * eta - 2.0)); + } else { + for (int i = 0; ((i < sumkmax) && (enough == 0)); i++) { + mk = G0os / (i + 2) / (i + 2); + sk = (sk * f1 - lk * eta) * (i + 1) * mk; + lk = mk * (i + 1) * lk; + sum = sum + sk; + if (robust::ratio((sk * sk), (sum * sum)) < (cutoff * cutoff)) { + enough = 1; + } + } + if (enough == 0) { +#ifndef NDEBUG + PORTABLE_WARN("Hugoniot Temperature not converged"); +#endif // NDEBUG + } + // printf("sum=%e\n",sum); + temp = _T0 - pf * ((G0os - 3.0) + exp(-G0os) * (G0os * G0os - 4.0 * G0os + 2.0) * + (std::log(f1) + sum)); + temp = temp * exp(_G0 * eta); + temp = temp - pf / f1 * ((4.0 - G0os) - 1.0 / f1); + } + return temp; +} + +template +PORTABLE_INLINE_FUNCTION Real MGUsup::InternalEnergyFromDensityTemperature( + const Real rho, const Real temp, Indexer_t &&lambda) const { + Real value = + HugInternalEnergyFromDensity(rho) + _Cv0 * (temp - HugTemperatureFromDensity(rho)); + return value; +} +template +PORTABLE_INLINE_FUNCTION Real MGUsup::PressureFromDensityTemperature( + const Real rho, const Real temp, Indexer_t &&lambda) const { + Real value = HugPressureFromDensity(rho) + + _G0 * _rho0 * _Cv0 * (temp - HugTemperatureFromDensity(rho)); + return value; +} +template +PORTABLE_INLINE_FUNCTION Real MGUsup::EntropyFromDensityTemperature( + const Real rho, const Real temp, Indexer_t &&lambda) const { + Real eta = 1.0 - robust::ratio(_rho0, rho); + Real value = _S0 - _G0 * _Cv0 * eta + _Cv0 * std::log(temp / _T0); + return value; +} +template +PORTABLE_INLINE_FUNCTION Real MGUsup::TExpansionCoeffFromDensityTemperature( + const Real rho, const Real temp, Indexer_t &&lambda) const { + Real value = + robust::ratio(_Cv0 * _rho0 * _G0, TBulkModulusFromDensityTemperature(rho, temp)); + return value; +} +template +PORTABLE_INLINE_FUNCTION Real MGUsup::TBulkModulusFromDensityTemperature( + const Real rho, const Real temp, Indexer_t &&lambda) const { + Real eta = 1.0 - robust::ratio(_rho0, rho); + Real value = robust::ratio((1.0 + _s * eta - _G0 * _s * eta * eta), (1.0 - _s * eta)); + if (eta == 0.0) { + value = _Cs * _Cs * _rho0; + } else { + value = value * robust::ratio(HugPressureFromDensity(rho), eta); + } + value = value - _G0 * _G0 * _Cv0 * _rho0 * HugTemperatureFromDensity(rho); + value = robust::ratio(_rho0, rho) * value; + return value; +} +template +PORTABLE_INLINE_FUNCTION Real MGUsup::BulkModulusFromDensityTemperature( + const Real rho, const Real temp, Indexer_t &&lambda) const { + Real eta = 1.0 - robust::ratio(_rho0, rho); + Real value = + robust::ratio((1.0 + _s * eta - _G0 * _s * eta * eta), eta * (1.0 - _s * eta)); + if (eta == 0.0) { + value = _Cs * _Cs * _rho0; + } else { + value = value * robust::ratio(HugPressureFromDensity(rho), eta); + } + value = value - _G0 * _G0 * _Cv0 * _rho0 * (temp - HugTemperatureFromDensity(rho)); + value = robust::ratio(_rho0, rho) * value; + return value; +} +template +PORTABLE_INLINE_FUNCTION Real MGUsup::TemperatureFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda) const { + Real value = + (sie - HugInternalEnergyFromDensity(rho)) / _Cv0 + HugTemperatureFromDensity(rho); + if (value < 0.0) { +#ifndef NDEBUG + PORTABLE_WARN("Negative temperature"); +#endif // NDEBUG + value = 1.e-12; + } + return value; +} +template +PORTABLE_INLINE_FUNCTION Real MGUsup::PressureFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda) const { + Real value = HugPressureFromDensity(rho) + + _rho0 * _G0 * (sie - HugInternalEnergyFromDensity(rho)); + return value; +} +template +PORTABLE_INLINE_FUNCTION Real +MGUsup::MinInternalEnergyFromDensity(const Real rho, Indexer_t &&lambda) const { + MinInternalEnergyIsNotEnabled("MGUsup"); + return 0.0; +} +template +PORTABLE_INLINE_FUNCTION Real MGUsup::EntropyFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda) const { + Real eta = 1.0 - robust::ratio(_rho0, rho); + Real value = std::log(TemperatureFromDensityInternalEnergy(rho, sie) / _T0); + value = _S0 - _G0 * _Cv0 * eta + _Cv0 * value; + if (value < 0.0) { +#ifndef NDEBUG + PORTABLE_WARN("Negative entropy"); +#endif // NDEBUG + value = 1.e-12; + } + return value; +} +template +PORTABLE_INLINE_FUNCTION Real MGUsup::BulkModulusFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda) const { + Real eta = 1.0 - robust::ratio(_rho0, rho); + Real value = robust::ratio((1.0 + _s * eta - _G0 * _s * eta * eta), (1.0 - _s * eta)); + if (eta == 0.0) { + value = _Cs * _Cs * _rho0; + } else { + value = value * robust::ratio(HugPressureFromDensity(rho), eta); + } + value = value + _G0 * _G0 * _rho0 * (sie - HugInternalEnergyFromDensity(rho)); + value = robust::ratio(_rho0, rho) * value; + return value; +} +// AEM: Give error since function is not well defined +template +PORTABLE_INLINE_FUNCTION void MGUsup::DensityEnergyFromPressureTemperature( + const Real press, const Real temp, Indexer_t &&lambda, Real &rho, Real &sie) const { + EOS_ERROR("MGUsup::DensityEnergyFromPressureTemperature: " + "Not implemented.\n"); +} +// AEM: We should add entropy and Gruneissen parameters here so that it is complete +// If we add also alpha and BT, those should also be in here. +template +PORTABLE_INLINE_FUNCTION void +MGUsup::FillEos(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, Real &bmod, + const unsigned long output, Indexer_t &&lambda) const { + const unsigned long input = ~output; // everything that is not output is input + if (thermalqs::density & output) { + EOS_ERROR("MGUsup FillEos: Density is required input.\n"); + } else if (thermalqs::temperature & output && + thermalqs::specific_internal_energy & output) { + EOS_ERROR("MGUsup FillEos: Density and Internal Energy or Density and Temperature " + "are required input parameters.\n"); + } + if (thermalqs::temperature & input) { + sie = InternalEnergyFromDensityTemperature(rho, temp); + } + if (output & thermalqs::temperature) + temp = TemperatureFromDensityInternalEnergy(rho, sie); + if (output & thermalqs::specific_internal_energy) sie = sie; + if (output & thermalqs::pressure) press = PressureFromDensityInternalEnergy(rho, sie); + if (output & thermalqs::specific_heat) + cv = SpecificHeatFromDensityInternalEnergy(rho, sie); + if (output & thermalqs::bulk_modulus) + bmod = BulkModulusFromDensityInternalEnergy(rho, sie); +} + +// TODO(JMM): pre-cache these rather than recomputing them each time +template +PORTABLE_INLINE_FUNCTION void +MGUsup::ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, + Real &bmod, Real &dpde, Real &dvdt, + Indexer_t &&lambda) const { + // AEM: Added all variables I think should be output eventually + // Real tbmod; + // Real entropy, alpha, Gamma; + + rho = _rho0; + temp = _T0; + sie = _E0; + press = PressureFromDensityTemperature(rho, temp, lambda); + // entropy = _S0; + cv = _Cv0; + // tbmod = _Cs * _Cs * _rho0 - _G0 * _G0 * _Cv0 * _rho0 * _T0; + // alpha = _A0; + bmod = _Cs * _Cs * _rho0; + // Gamma = _G0; + // AEM: I suggest taking the two following away. + dpde = _G0 * _rho0; + dvdt = robust::ratio(-1.0, _T0 * _G0 * _rho0); +} +} // namespace singularity + +#endif // _SINGULARITY_EOS_EOS_MGUSUP_HPP_ diff --git a/singularity-eos/eos/eos_models.hpp b/singularity-eos/eos/eos_models.hpp new file mode 100644 index 0000000000..306de6fb28 --- /dev/null +++ b/singularity-eos/eos/eos_models.hpp @@ -0,0 +1,41 @@ +//------------------------------------------------------------------------------ +// © 2021-2024. Triad National Security, LLC. All rights reserved. This +// program was produced under U.S. Government contract 89233218CNA000001 +// for Los Alamos National Laboratory (LANL), which is operated by Triad +// National Security, LLC for the U.S. Department of Energy/National +// Nuclear Security Administration. All rights in the program are +// reserved by Triad National Security, LLC, and the U.S. Department of +// Energy/National Nuclear Security Administration. The Government is +// granted for itself and others acting on its behalf a nonexclusive, +// paid-up, irrevocable worldwide license in this material to reproduce, +// prepare derivative works, distribute copies to the public, perform +// publicly and display publicly, and to permit others to do so. +//------------------------------------------------------------------------------ + +#ifndef _SINGULARITY_EOS_EOS_EOS_MODELS_HPP_ +#define _SINGULARITY_EOS_EOS_EOS_MODELS_HPP_ + +// EOS models +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// Modifiers +#include +#include +#include +#include +#include + +#endif // _SINGULARITY_EOS_EOS_EOS_MODELS_HPP_ diff --git a/singularity-eos/eos/eos_noble_abel.hpp b/singularity-eos/eos/eos_noble_abel.hpp index fc2edd49c4..898f1b8a3d 100644 --- a/singularity-eos/eos/eos_noble_abel.hpp +++ b/singularity-eos/eos/eos_noble_abel.hpp @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// © 2021-2023. Triad National Security, LLC. All rights reserved. This +// © 2021-2024. Triad National Security, LLC. All rights reserved. This // program was produced under U.S. Government contract 89233218CNA000001 // for Los Alamos National Laboratory (LANL), which is operated by Triad // National Security, LLC for the U.S. Department of Energy/National @@ -57,8 +57,10 @@ class NobleAbel : public EosBase { checkParams(); } NobleAbel GetOnDevice() { return *this; } + template PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { return std::max(robust::SMALL(), (sie - _qq) / _Cv); } PORTABLE_INLINE_FUNCTION void checkParams() const { @@ -66,77 +68,102 @@ class NobleAbel : public EosBase { PORTABLE_ALWAYS_REQUIRE(_gm1 >= 0, "Gruneisen parameter must be positive"); PORTABLE_ALWAYS_REQUIRE(_bb >= 0, "Covolume must be positive"); } + template PORTABLE_INLINE_FUNCTION Real InternalEnergyFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { return std::max(_qq, _Cv * temperature + _qq); } + template PORTABLE_INLINE_FUNCTION Real PressureFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { return std::max(robust::SMALL(), robust::ratio(_gm1 * rho * _Cv * temperature, 1.0 - _bb * rho)); } + template PORTABLE_INLINE_FUNCTION Real PressureFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { return std::max(robust::SMALL(), robust::ratio(_gm1 * rho * (sie - _qq), 1.0 - _bb * rho)); } - PORTABLE_INLINE_FUNCTION Real - MinInternalEnergyFromDensity(const Real rho, Real *lambda = nullptr) const { - MinInternalEnergyIsNotEnabled("Noble Abel"); - return 0.0; + template + PORTABLE_INLINE_FUNCTION Real MinInternalEnergyFromDensity( + const Real rho, Indexer_t &&lambda = static_cast(nullptr)) const { + return _qq; } - PORTABLE_INLINE_FUNCTION Real EntropyFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + template + PORTABLE_INLINE_FUNCTION Real + EntropyFromDensityTemperature(const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { const Real vol = robust::ratio(1.0, rho); return _Cv * std::log(robust::ratio(temperature, _T0) + robust::SMALL()) + _gm1 * _Cv * std::log(robust::ratio(vol - _bb, _vol0 - _bb) + robust::SMALL()) + _qp; } + template PORTABLE_INLINE_FUNCTION Real EntropyFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { const Real vol = robust::ratio(1.0, rho); return _Cv * std::log(robust::ratio(sie - _qq, _sie0 - _qq) + robust::SMALL()) + _gm1 * _Cv * std::log(robust::ratio(vol - _bb, _vol0 - _bb) + robust::SMALL()) + _qp; } + template PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { return _Cv; } + template PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { return _Cv; } + template PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { return std::max(robust::SMALL(), robust::ratio(_gm1 * (_gm1 + 1.0) * rho * _Cv * temperature, (1.0 - _bb * rho) * (1.0 - _bb * rho))); } + template PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { return std::max(robust::SMALL(), robust::ratio(_gm1 * (_gm1 + 1.0) * rho * (sie - _qq), (1.0 - _bb * rho) * (1.0 - _bb * rho))); } + template PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { return robust::ratio(_gm1, (1.0 - _bb * rho)); } + template PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { return robust::ratio(_gm1, (1.0 - _bb * rho)); } - PORTABLE_INLINE_FUNCTION void FillEos(Real &rho, Real &temp, Real &energy, Real &press, - Real &cv, Real &bmod, const unsigned long output, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - void ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, - Real &bmod, Real &dpde, Real &dvdt, - Real *lambda = nullptr) const { + template + PORTABLE_INLINE_FUNCTION void + FillEos(Real &rho, Real &temp, Real &energy, Real &press, Real &cv, Real &bmod, + const unsigned long output, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION void + ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, + Real &bmod, Real &dpde, Real &dvdt, + Indexer_t &&lambda = static_cast(nullptr)) const { // use STP: 1 atmosphere, room temperature rho = _rho0; temp = _T0; @@ -161,9 +188,10 @@ class NobleAbel : public EosBase { "%g\n", _gm1 + 1.0, _Cv, _bb, _qq); } + template PORTABLE_INLINE_FUNCTION void - DensityEnergyFromPressureTemperature(const Real press, const Real temp, Real *lambda, - Real &rho, Real &sie) const { + DensityEnergyFromPressureTemperature(const Real press, const Real temp, + Indexer_t &&lambda, Real &rho, Real &sie) const { sie = std::max(_qq, _Cv * temp + _qq); rho = std::max(robust::SMALL(), robust::ratio(press, _gm1 * _Cv * temp + _bb * press)); @@ -184,9 +212,10 @@ class NobleAbel : public EosBase { thermalqs::density | thermalqs::specific_internal_energy; }; -PORTABLE_INLINE_FUNCTION -void NobleAbel::FillEos(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, - Real &bmod, const unsigned long output, Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION void +NobleAbel::FillEos(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, Real &bmod, + const unsigned long output, Indexer_t &&lambda) const { if (output & thermalqs::density && output & thermalqs::specific_internal_energy) { if (output & thermalqs::pressure || output & thermalqs::temperature) { UNDEFINED_ERROR; diff --git a/singularity-eos/eos/eos_powermg.hpp b/singularity-eos/eos/eos_powermg.hpp new file mode 100644 index 0000000000..d73a994a5a --- /dev/null +++ b/singularity-eos/eos/eos_powermg.hpp @@ -0,0 +1,491 @@ +//------------------------------------------------------------------------------ +// © 2021-2024. Triad National Security, LLC. All rights reserved. This +// program was produced under U.S. Government contract 89233218CNA000001 +// for Los Alamos National Laboratory (LANL), which is operated by Triad +// National Security, LLC for the U.S. Department of Energy/National +// Nuclear Security Administration. All rights in the program are +// reserved by Triad National Security, LLC, and the U.S. Department of +// Energy/National Nuclear Security Administration. The Government is +// granted for itself and others acting on its behalf a nonexclusive, +// paid-up, irrevocable worldwide license in this material to reproduce, +// prepare derivative works, distribute copies to the public, perform +// publicly and display publicly, and to permit others to do so. +//------------------------------------------------------------------------------ + +#ifndef _SINGULARITY_EOS_EOS_POWERMG_HPP_ +#define _SINGULARITY_EOS_EOS_POWERMG_HPP_ + +#include +#include + +#include + +#include +#include +#include +#include +#include + +namespace singularity { + +using namespace eos_base; +using namespace robust; + +// COMMENT: This is a complete, thermodynamically consistent Mie-Gruneisen +// EOS based on a power series in eta for the Hugoniot pressure. +class PowerMG : public EosBase { + public: + PowerMG() = default; + // Constructor + PowerMG(const Real rho0, const Real T0, const Real G0, const Real Cv0, const Real E0, + const Real S0, const Real Pmin, const Real *expconsts) + : _rho0(rho0), _T0(T0), _G0(G0), _Cv0(Cv0), _E0(E0), _S0(S0), _Pmin(Pmin) { + _InitializePowerMG(expconsts); + _CheckPowerMG(); + } + + PowerMG GetOnDevice() { return *this; } + template + PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real InternalEnergyFromDensityTemperature( + const Real rho, const Real temp, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real + PressureFromDensityTemperature(const Real rho, const Real temp, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real PressureFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real MinInternalEnergyFromDensity( + const Real rho, Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real + EntropyFromDensityTemperature(const Real rho, const Real temp, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real EntropyFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityTemperature( + const Real rho, const Real temp, + Indexer_t &&lambda = static_cast(nullptr)) const { + return _Cv0; + } + template + PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { + return _Cv0; + } + // added for testing AEM Dec 2023 + PORTABLE_INLINE_FUNCTION Real AllHugPressureFromDensity(const Real rho) const; + PORTABLE_INLINE_FUNCTION Real AllHugInternalEnergyFromDensity(const Real rho) const; + PORTABLE_INLINE_FUNCTION Real AllHugTemperatureFromDensity(const Real rho) const; + // Thermal Bulk Modulus added AEM Dec 2022 + template + PORTABLE_INLINE_FUNCTION Real TBulkModulusFromDensityTemperature( + const Real rho, const Real temp, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityTemperature( + const Real rho, const Real temp, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + // Thermal expansion coefficient added AEM 2022 + template + PORTABLE_INLINE_FUNCTION Real TExpansionCoeffFromDensityTemperature( + const Real rho, const Real temp, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityTemperature( + const Real rho, const Real temp, + Indexer_t &&lambda = static_cast(nullptr)) const { + return robust::ratio(_G0 * _rho0, rho); + } + template + PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { + return robust::ratio(_G0 * _rho0, rho); + } + template + PORTABLE_INLINE_FUNCTION void + FillEos(Real &rho, Real &temp, Real &energy, Real &press, Real &cv, Real &bmod, + const unsigned long output, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION void + ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, + Real &bmod, Real &dpde, Real &dvdt, + Indexer_t &&lambda = static_cast(nullptr)) const; + // Generic functions provided by the base class. These contain e.g. the vector + // overloads that use the scalar versions declared here + SG_ADD_BASE_CLASS_USINGS(PowerMG) + PORTABLE_INLINE_FUNCTION + int nlambda() const noexcept { return 0; } + static constexpr unsigned long PreferredInput() { return _preferred_input; } + static inline unsigned long scratch_size(std::string method, unsigned int nelements) { + return 0; + } + static inline unsigned long max_scratch_size(unsigned int nelements) { return 0; } + PORTABLE_INLINE_FUNCTION void PrintParams() const { + static constexpr char st[]{"PowerMG Params: "}; + printf("%s rho0:%e T0:%e G0:%e Cv0:%e E0:%e S0:%e Pmin:%e\n" + "non-zero elements in K0toK40 array:\n", + st, _rho0, _T0, _G0, _Cv0, _E0, _S0, _Pmin); + for (int i = 0; i < 41; i++) { + if (_K0toK40[i] * _K0toK40[i] > 0.0) printf("K%i:%e\t", i, _K0toK40[i]); + } + printf("\n\n"); + } + // Density/Energy from P/T not unique, if used will give error + template + PORTABLE_INLINE_FUNCTION void + DensityEnergyFromPressureTemperature(const Real press, const Real temp, + Indexer_t &&lambda, Real &rho, Real &sie) const; + inline void Finalize() {} + static std::string EosType() { return std::string("PowerMG"); } + static std::string EosPyType() { return EosType(); } + + private: + static constexpr const unsigned long _preferred_input = + thermalqs::density | thermalqs::specific_internal_energy; + Real _rho0, _T0, _G0, _Cv0, _E0, _S0, _Pmin; + static constexpr const int PressureCoeffsK0toK40Size = 41; + int _M; + Real _K0toK40[PressureCoeffsK0toK40Size]; + void _CheckPowerMG(); + void _InitializePowerMG(const Real *expcoeffs); + PORTABLE_INLINE_FUNCTION Real _HugPressureFromDensity(const Real rho) const; + PORTABLE_INLINE_FUNCTION Real _HugTemperatureFromDensity(const Real rho) const; + PORTABLE_INLINE_FUNCTION Real _SN2Mp2(const Real x) const; + PORTABLE_INLINE_FUNCTION Real + _compBulkModulusFromDensityTemperature(const Real rho, const Real temp) const; + PORTABLE_INLINE_FUNCTION Real + _compBulkModulusFromDensityInternalEnergy(const Real rho, const Real sie) const; +}; + +inline void PowerMG::_CheckPowerMG() { + + if (_rho0 < 0.0) { + PORTABLE_ALWAYS_THROW_OR_ABORT("Required PowerMG model parameter rho0 < 0"); + } + if (_T0 < 0.0) { + PORTABLE_ALWAYS_THROW_OR_ABORT("Required PowerMG model parameter T0 < 0"); + } + if (_Cv0 < 0.0) { + PORTABLE_ALWAYS_THROW_OR_ABORT("Required PowerMG model parameter Cv0 < 0"); + } + if (_K0toK40[0] < 0.0) { + PORTABLE_ALWAYS_THROW_OR_ABORT("Required PowerMG model parameter K0 < 0"); + } + if (_Pmin >= 0.0) { + _Pmin = -1000 * _K0toK40[0]; +#ifndef NDEBUG + PORTABLE_WARN( + "PowerMG model parameter Pmin not set or positive. Reset to default (-1000*K0)"); +#endif // NDEBUG + } +} + +inline void PowerMG::_InitializePowerMG(const Real *K0toK40input) { + + // The PressureCoeffsK0toK40Size (=41) allowed K0 to K40 coefficients + // for the pressure reference curve vs rho + // are seldom all used so did not want to crowd the argument list with them. + // Instead I ask the host code to send me a pointer to this array so that I can + // copy it here. Not used coeffs should be set to 0.0 (of course). + _M = 0; + for (int ind = 0; ind < PressureCoeffsK0toK40Size; ind++) { + _K0toK40[ind] = K0toK40input[ind]; + if (_K0toK40[ind] != 0.0) _M = ind; + } +} + +PORTABLE_INLINE_FUNCTION Real PowerMG::_HugPressureFromDensity(Real rho) const { + const Real eta = 1.0 - robust::ratio(_rho0, rho); + Real value = 0.0; + for (int ind = _M; ind >= 1; ind--) { + value = eta * value + _K0toK40[ind]; + } + value = _K0toK40[0] * eta * (eta * value + 1.0); + return value; +} +PORTABLE_INLINE_FUNCTION Real PowerMG::_HugTemperatureFromDensity(Real rho) const { + const Real eta = 1.0 - robust::ratio(_rho0, rho); + Real gamma2 = _SN2Mp2(_G0 * eta); + Real sum = _M * _K0toK40[_M] * gamma2; + for (int ind = _M - 1; ind >= 1; ind--) { + gamma2 = _G0 * eta / (ind + 2) * gamma2 + 1.0 / (ind + 2); + sum = eta * sum + ind * _K0toK40[ind] * gamma2; + } + Real temp = eta * eta * eta * sum * (_K0toK40[0] / _Cv0 / 2.0 / _rho0); + temp = _T0 * exp(eta * _G0) + temp; + return temp; +} +// The function S_2^N is described in Robinson's report (SAND2019-6025 +// equations 1.29-3nd 1.30 with n=M+2) and is the largest coefficient in +// the series in eta for the Hugoniot temperature, equation 1.34. Other +// coefficients are calculated recusively from this one according to equation 1.36. +PORTABLE_INLINE_FUNCTION Real PowerMG::_SN2Mp2(const Real x) const { + Real ind = _M + 2; + int maxind = 200; + Real ak = 1.0 / ind; + Real sum = ak; + Real pf = exp(x) - 1.0; + Real ek = pf * ak; + // Add terms to the series sum until the relative error ek + // is smaller than machine presision. + while ((ek > sum * 1.e-15) && (ind < maxind)) { + ind = ind + 1; + ak = ak * x / ind; + ek = pf * ak; + sum = sum + ak; + } + if (ind >= maxind) { +#ifndef NDEBUG + PORTABLE_WARN("Part of Hugoniot Temperature not converged"); +#endif // NDEBUG + } + return sum; +} + +PORTABLE_INLINE_FUNCTION Real PowerMG::AllHugPressureFromDensity(Real rho) const { + const Real eta = 1.0 - robust::ratio(_rho0, rho); + Real value = 0.0; + if (eta <= 0.0) { + if (eta < _Pmin / _K0toK40[0]) { + value = _Pmin; + } else { + value = _K0toK40[0] * eta; + } + } else { + value = _HugPressureFromDensity(rho); + } + return value; +} +PORTABLE_INLINE_FUNCTION Real PowerMG::AllHugInternalEnergyFromDensity(Real rho) const { + const Real eta = 1.0 - robust::ratio(_rho0, rho); + return _E0 + robust::ratio(eta, 2.0 * _rho0) * AllHugPressureFromDensity(rho); +} +PORTABLE_INLINE_FUNCTION Real PowerMG::AllHugTemperatureFromDensity(Real rho) const { + const Real eta = 1.0 - robust::ratio(_rho0, rho); + Real value = 0.0; + if (eta <= 0.0) { + value = _T0 * exp(eta * _G0); + } else { + value = _HugTemperatureFromDensity(rho); + } + return value; +} + +template +PORTABLE_INLINE_FUNCTION Real PowerMG::InternalEnergyFromDensityTemperature( + const Real rho, const Real temp, Indexer_t &&lambda) const { + Real value = AllHugInternalEnergyFromDensity(rho) + + _Cv0 * (temp - AllHugTemperatureFromDensity(rho)); + return value; +} +template +PORTABLE_INLINE_FUNCTION Real PowerMG::PressureFromDensityTemperature( + const Real rho, const Real temp, Indexer_t &&lambda) const { + Real value = AllHugPressureFromDensity(rho) + + _G0 * _rho0 * _Cv0 * (temp - AllHugTemperatureFromDensity(rho)); + return value; +} +template +PORTABLE_INLINE_FUNCTION Real PowerMG::EntropyFromDensityTemperature( + const Real rho, const Real temp, Indexer_t &&lambda) const { + const Real eta = 1.0 - robust::ratio(_rho0, rho); + Real value = _S0 - _G0 * _Cv0 * eta + _Cv0 * std::log(temp / _T0); + return value; +} +template +PORTABLE_INLINE_FUNCTION Real PowerMG::TExpansionCoeffFromDensityTemperature( + const Real rho, const Real temp, Indexer_t &&lambda) const { + Real value = + robust::ratio(_Cv0 * _rho0 * _G0, TBulkModulusFromDensityTemperature(rho, temp)); + return value; +} +template +PORTABLE_INLINE_FUNCTION Real PowerMG::TBulkModulusFromDensityTemperature( + const Real rho, const Real temp, Indexer_t &&lambda) const { + return BulkModulusFromDensityTemperature(rho, temp) - + _G0 * _G0 * _Cv0 * _rho0 * robust::ratio(_rho0, rho) * temp; +} +PORTABLE_INLINE_FUNCTION Real +PowerMG::_compBulkModulusFromDensityTemperature(const Real rho, const Real temp) const { + const Real eta = 1.0 - robust::ratio(_rho0, rho); + Real value = (1.0 - _G0 * eta / 2.0) * _K0toK40[0]; + Real sum = 0.0; + for (int ind = _M; ind >= 1; ind--) { + sum = sum * eta + ind * _K0toK40[ind] * eta; + } + value = value * sum; + value = value + robust::ratio(_HugPressureFromDensity(rho), eta); + value = value + _G0 * _G0 * _Cv0 * _rho0 * (temp - _HugTemperatureFromDensity(rho)); + value = robust::ratio(_rho0, rho) * value; + return value; +} +template +PORTABLE_INLINE_FUNCTION Real PowerMG::BulkModulusFromDensityTemperature( + const Real rho, const Real temp, Indexer_t &&lambda) const { + const Real eta = 1.0 - robust::ratio(_rho0, rho); + Real value; + if (eta <= 0.0) { + if (eta < _Pmin / _K0toK40[0]) { + value = _G0 * _G0 * _Cv0 * _rho0 * (temp - _T0 * exp(_G0 * eta)); + } else { + value = _K0toK40[0] + _G0 * _G0 * _Cv0 * _rho0 * (temp - _T0 * exp(_G0 * eta)); + } + value = robust::ratio(_rho0, rho) * value; + } else { + value = _compBulkModulusFromDensityTemperature(rho, temp); + } + return value; +} +PORTABLE_INLINE_FUNCTION Real +PowerMG::_compBulkModulusFromDensityInternalEnergy(const Real rho, const Real sie) const { + const Real eta = 1.0 - robust::ratio(_rho0, rho); + Real value = (1.0 - _G0 * eta / 2.0) * _K0toK40[0]; + Real sum = 0.0; + for (int ind = _M; ind >= 1; ind--) { + sum = sum * eta + ind * _K0toK40[ind] * eta; + } + value = value * sum; + value = value + robust::ratio(_HugPressureFromDensity(rho), eta); + value = value + _G0 * _G0 * _rho0 * (sie - AllHugInternalEnergyFromDensity(rho)); + value = robust::ratio(_rho0, rho) * value; + return value; +} +template +PORTABLE_INLINE_FUNCTION Real PowerMG::BulkModulusFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda) const { + const Real eta = 1.0 - robust::ratio(_rho0, rho); + Real value; + if (eta <= 0.0) { + if (eta < _Pmin / _K0toK40[0]) { + value = _G0 * _G0 * _rho0 * + (sie - _E0 + _Pmin / _rho0 * (_Pmin / _K0toK40[0] / 2.0 - eta)); + } else { + value = + _K0toK40[0] + _G0 * _G0 * _rho0 * (sie - _E0 - _K0toK40[0] * eta * eta / 2.0); + } + value = robust::ratio(_rho0, rho) * value; + } else { + value = _compBulkModulusFromDensityInternalEnergy(rho, sie); + } + return value; +} + +template +PORTABLE_INLINE_FUNCTION Real PowerMG::TemperatureFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda) const { + Real value = (sie - AllHugInternalEnergyFromDensity(rho)) / _Cv0 + + AllHugTemperatureFromDensity(rho); + if (value < 0.0) { +#ifndef NDEBUG + PORTABLE_WARN("Negative temperature"); +#endif // NDEBUG + value = 1.e-12; + } + return value; +} +template +PORTABLE_INLINE_FUNCTION Real PowerMG::PressureFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda) const { + Real value = AllHugPressureFromDensity(rho) + + _rho0 * _G0 * (sie - AllHugInternalEnergyFromDensity(rho)); + return value; +} +template +PORTABLE_INLINE_FUNCTION Real +PowerMG::MinInternalEnergyFromDensity(const Real rho, Indexer_t &&lambda) const { + MinInternalEnergyIsNotEnabled("PowerMG"); + return 0.0; +} +template +PORTABLE_INLINE_FUNCTION Real PowerMG::EntropyFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda) const { + const Real eta = 1.0 - robust::ratio(_rho0, rho); + Real value = std::log(TemperatureFromDensityInternalEnergy(rho, sie) / _T0); + value = _S0 - _G0 * _Cv0 * eta + _Cv0 * value; + if (value < 0.0) { +#ifndef NDEBUG + PORTABLE_WARN("Negative entropy"); +#endif // NDEBUG + value = 1.e-12; + } + return value; +} +// AEM: Give error since function is not well defined +template +PORTABLE_INLINE_FUNCTION void PowerMG::DensityEnergyFromPressureTemperature( + const Real press, const Real temp, Indexer_t &&lambda, Real &rho, Real &sie) const { + EOS_ERROR("PowerMG::DensityEnergyFromPressureTemperature: " + "Not implemented.\n"); +} +// AEM: We should add entropy and Gruneissen parameters here so that it is complete +// If we add also alpha and BT, those should also be in here. +template +PORTABLE_INLINE_FUNCTION void +PowerMG::FillEos(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, Real &bmod, + const unsigned long output, Indexer_t &&lambda) const { + const unsigned long input = ~output; // everything that is not output is input + if (thermalqs::density & output) { + EOS_ERROR("PowerMG FillEos: Density is required input.\n"); + } else if (thermalqs::temperature & output && + thermalqs::specific_internal_energy & output) { + EOS_ERROR("PowerMG FillEos: Density and Internal Energy or Density and Temperature " + "are required input parameters.\n"); + } + if (thermalqs::temperature & input) { + sie = InternalEnergyFromDensityTemperature(rho, temp); + } + if (output & thermalqs::temperature) + temp = TemperatureFromDensityInternalEnergy(rho, sie); + if (output & thermalqs::specific_internal_energy) sie = sie; + if (output & thermalqs::pressure) press = PressureFromDensityInternalEnergy(rho, sie); + if (output & thermalqs::specific_heat) + cv = SpecificHeatFromDensityInternalEnergy(rho, sie); + if (output & thermalqs::bulk_modulus) + bmod = BulkModulusFromDensityInternalEnergy(rho, sie); +} + +// TODO(JMM): pre-cache these rather than recomputing them each time +template +PORTABLE_INLINE_FUNCTION void +PowerMG::ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, + Real &bmod, Real &dpde, Real &dvdt, + Indexer_t &&lambda) const { + // AEM: Added all variables I think should be output eventually + // Real tbmod; + // Real entropy, alpha, Gamma; + + rho = _rho0; + temp = _T0; + sie = _E0; + press = PressureFromDensityTemperature(rho, temp, lambda); + // entropy = _S0; + cv = _Cv0; + // tbmod = _K0toK40[0] - _G0 * _G0 * _Cv0 * _rho0 * _T0; + // alpha = _A0; + bmod = _K0toK40[0]; + // Gamma = _G0; + // AEM: I suggest taking the two following away. + dpde = _G0 * _rho0; + dvdt = robust::ratio(-1.0, _T0 * _G0 * _rho0); +} +} // namespace singularity + +#endif // _SINGULARITY_EOS_EOS_POWERMG_HPP_ diff --git a/singularity-eos/eos/eos_sap_polynomial.hpp b/singularity-eos/eos/eos_sap_polynomial.hpp index c5d0369c7c..8499de7c59 100644 --- a/singularity-eos/eos/eos_sap_polynomial.hpp +++ b/singularity-eos/eos/eos_sap_polynomial.hpp @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// © 2021-2023. Triad National Security, LLC. All rights reserved. This +// © 2021-2024. Triad National Security, LLC. All rights reserved. This // program was produced under U.S. Government contract 89233218CNA000001 // for Los Alamos National Laboratory (LANL), which is operated by Triad // National Security, LLC for the U.S. Department of Energy/National @@ -49,23 +49,31 @@ class SAP_Polynomial : public EosBase { PORTABLE_INLINE_FUNCTION void checkParams() const { PORTABLE_ALWAYS_REQUIRE(_rho0 >= 0, "Reference density must be non-negative"); } + template PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { PORTABLE_WARN("This function is a stub for an incomplete EoS."); return 0.0; } + template PORTABLE_INLINE_FUNCTION Real InternalEnergyFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { PORTABLE_WARN("This function is a stub for an incomplete EoS."); return 0.0; } + template PORTABLE_INLINE_FUNCTION Real PressureFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { PORTABLE_WARN("This function is a stub for an incomplete EoS."); return 0.0; } + template PORTABLE_INLINE_FUNCTION Real PressureFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { const Real mu = MuFromDensity(rho); if (mu >= 0) // Compression return _a0 + _a1 * mu + _a2c * mu * mu + _a3 * mu * mu * mu + @@ -75,52 +83,69 @@ class SAP_Polynomial : public EosBase { sie * (_b0 + _b1 * mu + _b2e * mu * mu + _b3 * mu * mu * mu); } - PORTABLE_INLINE_FUNCTION Real - MinInternalEnergyFromDensity(const Real rho, Real *lambda = nullptr) const { + template + PORTABLE_INLINE_FUNCTION Real MinInternalEnergyFromDensity( + const Real rho, Indexer_t &&lambda = static_cast(nullptr)) const { MinInternalEnergyIsNotEnabled("SAP Polynomial"); return 0.0; }; - PORTABLE_INLINE_FUNCTION Real EntropyFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + template + PORTABLE_INLINE_FUNCTION Real + EntropyFromDensityTemperature(const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { PORTABLE_WARN("This function is a stub for an incomplete EoS."); return 0.0; } + template PORTABLE_INLINE_FUNCTION Real EntropyFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { PORTABLE_WARN("This function is a stub for an incomplete EoS."); return 0.0; } + template PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { PORTABLE_WARN("This function is a stub for an incomplete EoS."); return 0.0; } + template PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { PORTABLE_WARN("This function is a stub for an incomplete EoS."); return 0.0; } + template PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { PORTABLE_WARN("This function is a stub for an incomplete EoS."); return 0.0; } + template PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { PORTABLE_WARN("This function is a stub for an incomplete EoS."); return 0.0; } + template PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { const Real mu = MuFromDensity(rho); if (mu >= 0) // Compression return _b0 + _b1 * mu + _b2c * mu * mu + _b3 * mu * mu * mu; else return _b0 + _b1 * mu + _b2e * mu * mu + _b3 * mu * mu * mu; } + template PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { const Real mu = MuFromDensity(rho); if (mu >= 0) // Compression return (1 + mu) * (_a1 + 2 * _a2c * mu + 3 * _a3 * mu * mu + @@ -129,19 +154,23 @@ class SAP_Polynomial : public EosBase { return (1 + mu) * (_a1 + 2 * _a2e * mu + 3 * _a3 * mu * mu + sie * (_b1 + 2 * _b2e * mu + 3 * _b3 * mu * mu)); } - PORTABLE_INLINE_FUNCTION Real MuFromDensity(const Real rho, - Real *lambda = nullptr) const { + template + PORTABLE_INLINE_FUNCTION Real + MuFromDensity(const Real rho, Indexer_t &&lambda = static_cast(nullptr)) const { return rho / _rho0 - 1; } - PORTABLE_INLINE_FUNCTION void FillEos(Real &rho, Real &temp, Real &energy, Real &press, - Real &cv, Real &bmod, const unsigned long output, - Real *lambda = nullptr) const; + template + PORTABLE_INLINE_FUNCTION void + FillEos(Real &rho, Real &temp, Real &energy, Real &press, Real &cv, Real &bmod, + const unsigned long output, + Indexer_t &&lambda = static_cast(nullptr)) const; - PORTABLE_INLINE_FUNCTION - void ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, - Real &bmod, Real &dpde, Real &dvdt, - Real *lambda = nullptr) const { + template + PORTABLE_INLINE_FUNCTION void + ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, + Real &bmod, Real &dpde, Real &dvdt, + Indexer_t &&lambda = static_cast(nullptr)) const { // use STP: 1 atmosphere, room temperature rho = _rho0; temp = 0.0; @@ -176,9 +205,10 @@ class SAP_Polynomial : public EosBase { printf(" b2e = %g\n", _b2e); printf(" b3 = %g\n", _b3); } + template PORTABLE_INLINE_FUNCTION void - DensityEnergyFromPressureTemperature(const Real press, const Real temp, Real *lambda, - Real &rho, Real &sie) const { + DensityEnergyFromPressureTemperature(const Real press, const Real temp, + Indexer_t &&lambda, Real &rho, Real &sie) const { PORTABLE_WARN("This function is a stub for an incomplete EoS."); sie = 0.0; rho = 0.0; @@ -196,9 +226,11 @@ class SAP_Polynomial : public EosBase { thermalqs::density | thermalqs::specific_internal_energy; }; -PORTABLE_INLINE_FUNCTION -void SAP_Polynomial::FillEos(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, - Real &bmod, const unsigned long output, Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION void SAP_Polynomial::FillEos(Real &rho, Real &temp, Real &sie, + Real &press, Real &cv, Real &bmod, + const unsigned long output, + Indexer_t &&lambda) const { if (output & thermalqs::density && output & thermalqs::specific_internal_energy) { if (output & thermalqs::pressure || output & thermalqs::temperature) { UNDEFINED_ERROR; diff --git a/singularity-eos/eos/eos_spiner.hpp b/singularity-eos/eos/eos_spiner.hpp index 6d830dc732..5e43209593 100644 --- a/singularity-eos/eos/eos_spiner.hpp +++ b/singularity-eos/eos/eos_spiner.hpp @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// © 2021-2023. Triad National Security, LLC. All rights reserved. This +// © 2021-2024. Triad National Security, LLC. All rights reserved. This // program was produced under U.S. Government contract 89233218CNA000001 // for Los Alamos National Laboratory (LANL), which is operated by Triad // National Security, LLC for the U.S. Department of Energy/National @@ -38,6 +38,7 @@ #include #include #include +#include #include // spiner @@ -104,56 +105,73 @@ class SpinerEOSDependsRhoT : public EosBase { inline SpinerEOSDependsRhoT GetOnDevice(); - PORTABLE_INLINE_FUNCTION - Real TemperatureFromDensityInternalEnergy(const Real rho, const Real sie, - Real *lambda = nullptr) const; + template + PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real MinInternalEnergyFromDensity( + const Real rho, Indexer_t &&lambda = static_cast(nullptr)) const; + + template + PORTABLE_INLINE_FUNCTION Real InternalEnergyFromDensityTemperature( + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const; + template PORTABLE_INLINE_FUNCTION Real - MinInternalEnergyFromDensity(const Real rho, Real *lambda = nullptr) const; - - PORTABLE_INLINE_FUNCTION - Real InternalEnergyFromDensityTemperature(const Real rho, const Real temperature, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real PressureFromDensityTemperature(const Real rho, const Real temperature, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real PressureFromDensityInternalEnergy(const Real rho, const Real sie, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real EntropyFromDensityTemperature(const Real rho, const Real temperature, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real EntropyFromDensityInternalEnergy(const Real rho, const Real sie, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real SpecificHeatFromDensityTemperature(const Real rho, const Real temperature, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real SpecificHeatFromDensityInternalEnergy(const Real rho, const Real sie, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real BulkModulusFromDensityTemperature(const Real rho, const Real temperature, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real BulkModulusFromDensityInternalEnergy(const Real rho, const Real sie, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real GruneisenParamFromDensityTemperature(const Real rho, const Real temperature, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real GruneisenParamFromDensityInternalEnergy(const Real rho, const Real sie, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - void DensityEnergyFromPressureTemperature(const Real press, const Real temp, - Real *lambda, Real &rho, Real &sie) const; - PORTABLE_INLINE_FUNCTION - void FillEos(Real &rho, Real &temp, Real &energy, Real &press, Real &cv, Real &bmod, - const unsigned long output, Real *lambda = nullptr) const; - - PORTABLE_INLINE_FUNCTION - void ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, - Real &bmod, Real &dpde, Real &dvdt, - Real *lambda = nullptr) const; + PressureFromDensityTemperature(const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real PressureFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real + EntropyFromDensityTemperature(const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real EntropyFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityTemperature( + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityTemperature( + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityTemperature( + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION void + DensityEnergyFromPressureTemperature(const Real press, const Real temp, + Indexer_t &&lambda, Real &rho, Real &sie) const; + template + PORTABLE_INLINE_FUNCTION void + FillEos(Real &rho, Real &temp, Real &energy, Real &press, Real &cv, Real &bmod, + const unsigned long output, + Indexer_t &&lambda = static_cast(nullptr)) const; + + template + PORTABLE_INLINE_FUNCTION void + ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, + Real &bmod, Real &dpde, Real &dvdt, + Indexer_t &&lambda = static_cast(nullptr)) const; PORTABLE_INLINE_FUNCTION Real RhoPmin(const Real temp) const; @@ -222,18 +240,22 @@ class SpinerEOSDependsRhoT : public EosBase { PORTABLE_FORCEINLINE_FUNCTION Real T_(const Real lT) const noexcept { return fromLog_(lT, lTOffset_); } - PORTABLE_INLINE_FUNCTION - Real lTFromlRhoSie_(const Real lRho, const Real sie, TableStatus &whereAmI, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real lTFromlRhoP_(const Real lRho, const Real press, TableStatus &whereAmI, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real lRhoFromPlT_(const Real P, const Real lT, TableStatus &whereAmI, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - void getLogsRhoT_(const Real rho, const Real temperature, Real &lRho, Real &lT, - Real *lambda = nullptr) const; + template + PORTABLE_INLINE_FUNCTION Real + lTFromlRhoSie_(const Real lRho, const Real sie, TableStatus &whereAmI, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real + lTFromlRhoP_(const Real lRho, const Real press, TableStatus &whereAmI, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real + lRhoFromPlT_(const Real P, const Real lT, TableStatus &whereAmI, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION void + getLogsRhoT_(const Real rho, const Real temperature, Real &lRho, Real &lT, + Indexer_t &&lambda = static_cast(nullptr)) const; PORTABLE_INLINE_FUNCTION Real sieFromlRhoTlT_(const Real lRho, const Real T, const Real lT, const TableStatus &whereAmI) const; @@ -336,57 +358,74 @@ class SpinerEOSDependsRhoSie : public EosBase { bool reproducibility_mode = false); inline SpinerEOSDependsRhoSie GetOnDevice(); - PORTABLE_INLINE_FUNCTION - Real TemperatureFromDensityInternalEnergy(const Real rho, const Real sie, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real InternalEnergyFromDensityTemperature(const Real rho, const Real T, - Real *lambda = nullptr) const; - - PORTABLE_INLINE_FUNCTION - Real PressureFromDensityTemperature(const Real rho, const Real T, - Real *lambda = nullptr) const; + template + PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real InternalEnergyFromDensityTemperature( + const Real rho, const Real T, + Indexer_t &&lambda = static_cast(nullptr)) const; - PORTABLE_INLINE_FUNCTION - Real PressureFromDensityInternalEnergy(const Real rho, const Real sie, - Real *lambda = nullptr) const; + template PORTABLE_INLINE_FUNCTION Real - MinInternalEnergyFromDensity(const Real rho, Real *lambda = nullptr) const; - - PORTABLE_INLINE_FUNCTION - Real EntropyFromDensityTemperature(const Real rho, const Real temperature, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real EntropyFromDensityInternalEnergy(const Real rho, const Real sie, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real SpecificHeatFromDensityTemperature(const Real rho, const Real T, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real SpecificHeatFromDensityInternalEnergy(const Real rho, const Real sie, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real BulkModulusFromDensityTemperature(const Real rho, const Real T, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real BulkModulusFromDensityInternalEnergy(const Real rho, const Real sie, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real GruneisenParamFromDensityTemperature(const Real rho, const Real T, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real GruneisenParamFromDensityInternalEnergy(const Real rho, const Real sie, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - void DensityEnergyFromPressureTemperature(const Real press, const Real temp, - Real *lambda, Real &rho, Real &sie) const; - PORTABLE_INLINE_FUNCTION - void FillEos(Real &rho, Real &temp, Real &energy, Real &press, Real &cv, Real &bmod, - const unsigned long output, Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - void ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, - Real &bmod, Real &dpde, Real &dvdt, - Real *lambda = nullptr) const; + PressureFromDensityTemperature(const Real rho, const Real T, + Indexer_t &&lambda = static_cast(nullptr)) const; + + template + PORTABLE_INLINE_FUNCTION Real PressureFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real MinInternalEnergyFromDensity( + const Real rho, Indexer_t &&lambda = static_cast(nullptr)) const; + + template + PORTABLE_INLINE_FUNCTION Real + EntropyFromDensityTemperature(const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real EntropyFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityTemperature( + const Real rho, const Real T, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityTemperature( + const Real rho, const Real T, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityTemperature( + const Real rho, const Real T, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION void + DensityEnergyFromPressureTemperature(const Real press, const Real temp, + Indexer_t &&lambda, Real &rho, Real &sie) const; + template + PORTABLE_INLINE_FUNCTION void + FillEos(Real &rho, Real &temp, Real &energy, Real &press, Real &cv, Real &bmod, + const unsigned long output, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION void + ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, + Real &bmod, Real &dpde, Real &dvdt, + Indexer_t &&lambda = static_cast(nullptr)) const; static constexpr unsigned long PreferredInput() { return _preferred_input; } static inline unsigned long scratch_size(std::string method, unsigned int nelements) { @@ -445,14 +484,17 @@ class SpinerEOSDependsRhoSie : public EosBase { static PORTABLE_FORCEINLINE_FUNCTION Real fromLog_(const Real lx, const Real offset) { return FastMath::pow10(lx) - offset; } - PORTABLE_INLINE_FUNCTION - Real interpRhoT_(const Real rho, const Real T, const DataBox &db, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real interpRhoSie_(const Real rho, const Real sie, const DataBox &db, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real lRhoFromPlT_(const Real P, const Real lT, Real *lambda) const; + template + PORTABLE_INLINE_FUNCTION Real + interpRhoT_(const Real rho, const Real T, const DataBox &db, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real + interpRhoSie_(const Real rho, const Real sie, const DataBox &db, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real lRhoFromPlT_(const Real P, const Real lT, + Indexer_t &&lambda) const; DataBox sie_; // depends on (rho,T) DataBox T_; // depends on (rho, sie) @@ -828,15 +870,15 @@ inline void SpinerEOSDependsRhoT::fixBulkModulus_() { for (int i = 0; i < numT_; i++) { Real lT = bMod_.range(0).x(i); Real press = P_.interpToReal(lRho, lT); - Real DPDR = dPdRho_.interpToReal(lRho, lT); - Real DPDE = dPdE_.interpToReal(lRho, lT); - Real DEDR = dEdRho_.interpToReal(lRho, lT); - Real DTDE = dTdE_.interpToReal(lRho, lT); + Real DPDR_E = dPdRho_.interpToReal(lRho, lT); + Real DPDE_R = dPdE_.interpToReal(lRho, lT); + Real DEDR_T = dEdRho_.interpToReal(lRho, lT); + Real DPDR_T = DPDR_E + DPDE_R * DEDR_T; Real bMod; - if (DPDE > 0.0 && rho > 0.0) { - bMod = rho * DPDR + DPDE * (press / rho - rho * DEDR); + if (DPDE_R > 0.0 && rho > 0.0) { + bMod = rho * DPDR_E + DPDE_R * (press / rho); } else if (rho > 0.0) { - bMod = std::max(rho * DPDR, 0.0); + bMod = std::max(rho * DPDR_T, 0.0); } else { bMod = 0.0; } @@ -906,40 +948,36 @@ inline void SpinerEOSDependsRhoT::setlTColdCrit_() { } } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoT::TemperatureFromDensityInternalEnergy(const Real rho, - const Real sie, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real SpinerEOSDependsRhoT::TemperatureFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda) const { TableStatus whereAmI; const Real lRho = lRho_(rho); const Real lT = lTFromlRhoSie_(lRho, sie, whereAmI, lambda); return T_(lT); } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoT::InternalEnergyFromDensityTemperature(const Real rho, - const Real temperature, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real SpinerEOSDependsRhoT::InternalEnergyFromDensityTemperature( + const Real rho, const Real temperature, Indexer_t &&lambda) const { Real lRho, lT; getLogsRhoT_(rho, temperature, lRho, lT, lambda); TableStatus whereAmI = getLocDependsRhoT_(lRho, lT); return sieFromlRhoTlT_(lRho, temperature, lT, whereAmI); } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoT::PressureFromDensityTemperature(const Real rho, - const Real temperature, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real SpinerEOSDependsRhoT::PressureFromDensityTemperature( + const Real rho, const Real temperature, Indexer_t &&lambda) const { Real lRho, lT; getLogsRhoT_(rho, temperature, lRho, lT, lambda); TableStatus whereAmI = getLocDependsRhoT_(lRho, lT); return PFromRholRhoTlT_(rho, lRho, temperature, lT, whereAmI); } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoT::PressureFromDensityInternalEnergy(const Real rho, - const Real sie, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real SpinerEOSDependsRhoT::PressureFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda) const { TableStatus whereAmI; Real lRho = lRho_(rho); Real lT = lTFromlRhoSie_(lRho, sie, whereAmI, lambda); @@ -955,41 +993,37 @@ Real SpinerEOSDependsRhoT::PressureFromDensityInternalEnergy(const Real rho, return P; } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoT::MinInternalEnergyFromDensity(const Real rho, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real SpinerEOSDependsRhoT::MinInternalEnergyFromDensity( + const Real rho, Indexer_t &&lambda) const { MinInternalEnergyIsNotEnabled("SpinerEOSDependsRhoT"); return 0.0; } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoT::EntropyFromDensityTemperature(const Real rho, - const Real temperature, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real SpinerEOSDependsRhoT::EntropyFromDensityTemperature( + const Real rho, const Real temperature, Indexer_t &&lambda) const { EntropyIsNotEnabled("SpinerEOSDependsRhoT"); return 1.0; } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoT::EntropyFromDensityInternalEnergy(const Real rho, - const Real sie, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real SpinerEOSDependsRhoT::EntropyFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda) const { EntropyIsNotEnabled("SpinerEOSDependsRhoT"); return 1.0; } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoT::SpecificHeatFromDensityTemperature(const Real rho, - const Real temperature, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real SpinerEOSDependsRhoT::SpecificHeatFromDensityTemperature( + const Real rho, const Real temperature, Indexer_t &&lambda) const { Real lRho, lT; getLogsRhoT_(rho, temperature, lRho, lT, lambda); TableStatus whereAmI = getLocDependsRhoT_(lRho, lT); return CvFromlRholT_(lRho, lT, whereAmI); } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoT::SpecificHeatFromDensityInternalEnergy(const Real rho, - const Real sie, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real SpinerEOSDependsRhoT::SpecificHeatFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda) const { TableStatus whereAmI; Real Cv; const Real lRho = lRho_(rho); @@ -1006,20 +1040,18 @@ Real SpinerEOSDependsRhoT::SpecificHeatFromDensityInternalEnergy(const Real rho, return Cv > robust::EPS() ? Cv : robust::EPS(); } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoT::BulkModulusFromDensityTemperature(const Real rho, - const Real temperature, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real SpinerEOSDependsRhoT::BulkModulusFromDensityTemperature( + const Real rho, const Real temperature, Indexer_t &&lambda) const { Real lRho, lT; getLogsRhoT_(rho, temperature, lRho, lT, lambda); TableStatus whereAmI = getLocDependsRhoT_(lRho, lT); return bModFromRholRhoTlT_(rho, lRho, temperature, lT, whereAmI); } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoT::GruneisenParamFromDensityTemperature(const Real rho, - const Real temp, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real SpinerEOSDependsRhoT::GruneisenParamFromDensityTemperature( + const Real rho, const Real temp, Indexer_t &&lambda) const { Real lRho, lT, gm1; getLogsRhoT_(rho, temp, lRho, lT, lambda); @@ -1037,10 +1069,9 @@ Real SpinerEOSDependsRhoT::GruneisenParamFromDensityTemperature(const Real rho, return gm1; } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoT::BulkModulusFromDensityInternalEnergy(const Real rho, - const Real sie, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real SpinerEOSDependsRhoT::BulkModulusFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda) const { TableStatus whereAmI; Real bMod; const Real lRho = lRho_(rho); @@ -1056,10 +1087,11 @@ Real SpinerEOSDependsRhoT::BulkModulusFromDensityInternalEnergy(const Real rho, return bMod; } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoT::GruneisenParamFromDensityInternalEnergy(const Real rho, - const Real sie, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real +SpinerEOSDependsRhoT::GruneisenParamFromDensityInternalEnergy(const Real rho, + const Real sie, + Indexer_t &&lambda) const { TableStatus whereAmI; Real gm1; const Real lRho = lRho_(rho); @@ -1077,11 +1109,9 @@ Real SpinerEOSDependsRhoT::GruneisenParamFromDensityInternalEnergy(const Real rh } // TODO(JMM): This would be faster with hand-tuned code -PORTABLE_INLINE_FUNCTION -void SpinerEOSDependsRhoT::DensityEnergyFromPressureTemperature(const Real press, - const Real temp, - Real *lambda, Real &rho, - Real &sie) const { +template +PORTABLE_INLINE_FUNCTION void SpinerEOSDependsRhoT::DensityEnergyFromPressureTemperature( + const Real press, const Real temp, Indexer_t &&lambda, Real &rho, Real &sie) const { TableStatus whereAmI; Real lT = lT_(temp); Real lRho = lRhoFromPlT_(press, lT, whereAmI, lambda); @@ -1089,10 +1119,11 @@ void SpinerEOSDependsRhoT::DensityEnergyFromPressureTemperature(const Real press sie = InternalEnergyFromDensityTemperature(rho, temp, lambda); } -PORTABLE_INLINE_FUNCTION -void SpinerEOSDependsRhoT::FillEos(Real &rho, Real &temp, Real &energy, Real &press, - Real &cv, Real &bmod, const unsigned long output, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION void +SpinerEOSDependsRhoT::FillEos(Real &rho, Real &temp, Real &energy, Real &press, Real &cv, + Real &bmod, const unsigned long output, + Indexer_t &&lambda) const { Real lRho, lT; TableStatus whereAmI; const unsigned long input = ~output; @@ -1135,17 +1166,16 @@ void SpinerEOSDependsRhoT::FillEos(Real &rho, Real &temp, Real &energy, Real &pr if (output & thermalqs::bulk_modulus) { bmod = bModFromRholRhoTlT_(rho, lRho, temp, lT, whereAmI); } - if (lambda != nullptr) { + if (!variadic_utils::is_nullptr(lambda)) { lambda[Lambda::lRho] = lRho; lambda[Lambda::lT] = lT; } } -PORTABLE_INLINE_FUNCTION -void SpinerEOSDependsRhoT::ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, - Real &press, Real &cv, Real &bmod, - Real &dpde, Real &dvdt, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION void SpinerEOSDependsRhoT::ValuesAtReferenceState( + Real &rho, Real &temp, Real &sie, Real &press, Real &cv, Real &bmod, Real &dpde, + Real &dvdt, Indexer_t &&lambda) const { rho = rhoNormal_; temp = TNormal_; sie = sieNormal_; @@ -1164,20 +1194,21 @@ Real SpinerEOSDependsRhoT::RhoPmin(const Real temp) const { return rho_at_pmin_.interpToReal(lT); } -PORTABLE_INLINE_FUNCTION -void SpinerEOSDependsRhoT::getLogsRhoT_(const Real rho, const Real temperature, - Real &lRho, Real &lT, Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION void +SpinerEOSDependsRhoT::getLogsRhoT_(const Real rho, const Real temperature, Real &lRho, + Real &lT, Indexer_t &&lambda) const { lRho = lRho_(rho); lT = lT_(temperature); - if (lambda != nullptr) { + if (!variadic_utils::is_nullptr(lambda)) { lambda[Lambda::lRho] = lRho; lambda[Lambda::lT] = lT; } } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoT::lRhoFromPlT_(const Real P, const Real lT, - TableStatus &whereAmI, Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real SpinerEOSDependsRhoT::lRhoFromPlT_( + const Real P, const Real lT, TableStatus &whereAmI, Indexer_t &&lambda) const { RootFinding1D::Status status = RootFinding1D::Status::SUCCESS; Real lRho; @@ -1185,7 +1216,7 @@ Real SpinerEOSDependsRhoT::lRhoFromPlT_(const Real P, const Real lT, // Real lRhoGuess = lRhoMin_ + 0.9*(lRhoMax_ - lRhoMin_); const RootFinding1D::RootCounts *pcounts = (memoryStatus_ == DataStatus::OnDevice) ? nullptr : &counts; - if (lambda != nullptr && lRhoMin_ <= lambda[Lambda::lRho] && + if (!variadic_utils::is_nullptr(lambda) && lRhoMin_ <= lambda[Lambda::lRho] && lambda[Lambda::lRho] <= lRhoMax_) { lRhoGuess = lambda[Lambda::lRho]; } @@ -1223,7 +1254,7 @@ Real SpinerEOSDependsRhoT::lRhoFromPlT_(const Real P, const Real lT, #endif // SPINER_EOS_VERBOSE lRho = reproducible_ ? lRhoMax_ : lRhoGuess; } - if (lambda != nullptr) { + if (!variadic_utils::is_nullptr(lambda)) { lambda[Lambda::lRho] = lRho; lambda[Lambda::lT] = lT; } @@ -1234,9 +1265,9 @@ Real SpinerEOSDependsRhoT::lRhoFromPlT_(const Real P, const Real lT, return lRho; } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoT::lTFromlRhoSie_(const Real lRho, const Real sie, - TableStatus &whereAmI, Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real SpinerEOSDependsRhoT::lTFromlRhoSie_( + const Real lRho, const Real sie, TableStatus &whereAmI, Indexer_t &&lambda) const { const RootFinding1D::RootCounts *pcounts = (memoryStatus_ == DataStatus::OnDevice) ? nullptr : &counts; @@ -1261,7 +1292,7 @@ Real SpinerEOSDependsRhoT::lTFromlRhoSie_(const Real lRho, const Real sie, } } else { Real lTGuess = reproducible_ ? lTMin_ : 0.5 * (lTMin_ + lTMax_); - if (lambda != nullptr && lTMin_ <= lambda[Lambda::lT] && + if (!variadic_utils::is_nullptr(lambda) && lTMin_ <= lambda[Lambda::lT] && lambda[Lambda::lT] <= lTMax_) { lTGuess = lambda[Lambda::lT]; } @@ -1285,7 +1316,7 @@ Real SpinerEOSDependsRhoT::lTFromlRhoSie_(const Real lRho, const Real sie, lT = reproducible_ ? lTMin_ : lTGuess; } } - if (lambda != nullptr) { + if (!variadic_utils::is_nullptr(lambda)) { lambda[Lambda::lRho] = lRho; lambda[Lambda::lT] = lT; } @@ -1296,9 +1327,9 @@ Real SpinerEOSDependsRhoT::lTFromlRhoSie_(const Real lRho, const Real sie, return lT; } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoT::lTFromlRhoP_(const Real lRho, const Real press, - TableStatus &whereAmI, Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real SpinerEOSDependsRhoT::lTFromlRhoP_( + const Real lRho, const Real press, TableStatus &whereAmI, Indexer_t &&lambda) const { const RootFinding1D::RootCounts *pcounts = (memoryStatus_ == DataStatus::OnDevice) ? nullptr : &counts; RootFinding1D::Status status = RootFinding1D::Status::SUCCESS; @@ -1321,7 +1352,7 @@ Real SpinerEOSDependsRhoT::lTFromlRhoP_(const Real lRho, const Real press, } } else { whereAmI = TableStatus::OnTable; - if (lambda != nullptr && lTMin_ <= lambda[Lambda::lT] && + if (!variadic_utils::is_nullptr(lambda) && lTMin_ <= lambda[Lambda::lT] && lambda[Lambda::lT] <= lTMax_) { lTGuess = lambda[Lambda::lT]; } else { @@ -1343,7 +1374,7 @@ Real SpinerEOSDependsRhoT::lTFromlRhoP_(const Real lRho, const Real press, lT = reproducible_ ? lTMin_ : lTGuess; } } - if (lambda != nullptr) { + if (!variadic_utils::is_nullptr(lambda)) { lambda[Lambda::lRho] = lRho; lambda[Lambda::lT] = lT; } @@ -1606,15 +1637,15 @@ inline void SpinerEOSDependsRhoSie::calcBMod_(SP5Tables &tables) { Real rho = fromLog_(lRho, lRhoOffset_); for (int i = 0; i < tables.bMod.dim(1); i++) { Real press = tables.P(j, i); - Real DPDR = tables.dPdRho(j, i); - Real DPDE = tables.dPdE(j, i); - Real DEDR = tables.dEdRho(j, i); - Real DTDE = tables.dTdE(j, i); + Real DPDR_E = tables.dPdRho(j, i); + Real DPDE_R = tables.dPdE(j, i); + Real DEDR_T = tables.dEdRho(j, i); + Real DPDR_T = DPDR_E + DPDE_R * DEDR_T; Real bMod; - if (DPDE > 0.0 && rho > 0.0) { - bMod = rho * DPDR + DPDE * (press / rho - rho * DEDR); + if (DPDE_R > 0.0 && rho > 0.0) { + bMod = rho * DPDR_E + DPDE_R * (press / rho); } else if (rho > 0.0) { - bMod = std::max(rho * DPDR, 0.0); + bMod = std::max(rho * DPDR_T, 0.0); } else { bMod = 0.0; } @@ -1690,115 +1721,115 @@ void SpinerEOSDependsRhoSie::Finalize() { memoryStatus_ = DataStatus::Deallocated; } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoSie::TemperatureFromDensityInternalEnergy(const Real rho, - const Real sie, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real +SpinerEOSDependsRhoSie::TemperatureFromDensityInternalEnergy(const Real rho, + const Real sie, + Indexer_t &&lambda) const { return interpRhoSie_(rho, sie, T_, lambda); } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoSie::InternalEnergyFromDensityTemperature(const Real rho, - const Real T, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real +SpinerEOSDependsRhoSie::InternalEnergyFromDensityTemperature(const Real rho, const Real T, + Indexer_t &&lambda) const { return interpRhoT_(rho, T, sie_, lambda); } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoSie::PressureFromDensityTemperature(const Real rho, const Real T, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real SpinerEOSDependsRhoSie::PressureFromDensityTemperature( + const Real rho, const Real T, Indexer_t &&lambda) const { return interpRhoT_(rho, T, dependsRhoT_.P, lambda); } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoSie::PressureFromDensityInternalEnergy(const Real rho, - const Real sie, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real SpinerEOSDependsRhoSie::PressureFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda) const { return interpRhoSie_(rho, sie, dependsRhoSie_.P, lambda); } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoSie::MinInternalEnergyFromDensity(const Real rho, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real SpinerEOSDependsRhoSie::MinInternalEnergyFromDensity( + const Real rho, Indexer_t &&lambda) const { MinInternalEnergyIsNotEnabled("SpinerEOSDependsRhoSie"); return 0.0; } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoSie::EntropyFromDensityTemperature(const Real rho, - const Real temperature, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real SpinerEOSDependsRhoSie::EntropyFromDensityTemperature( + const Real rho, const Real temperature, Indexer_t &&lambda) const { EntropyIsNotEnabled("SpinerEOSDependsRhoSie"); return 1.0; } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoSie::EntropyFromDensityInternalEnergy(const Real rho, - const Real sie, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real SpinerEOSDependsRhoSie::EntropyFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda) const { EntropyIsNotEnabled("SpinerEOSDependsRhoSie"); return 1.0; } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoSie::SpecificHeatFromDensityTemperature(const Real rho, - const Real T, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real SpinerEOSDependsRhoSie::SpecificHeatFromDensityTemperature( + const Real rho, const Real T, Indexer_t &&lambda) const { return 1. / interpRhoT_(rho, T, dependsRhoT_.dTdE, lambda); } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoSie::SpecificHeatFromDensityInternalEnergy(const Real rho, - const Real sie, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real +SpinerEOSDependsRhoSie::SpecificHeatFromDensityInternalEnergy(const Real rho, + const Real sie, + Indexer_t &&lambda) const { return 1. / interpRhoSie_(rho, sie, dependsRhoSie_.dTdE, lambda); } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoSie::BulkModulusFromDensityTemperature(const Real rho, - const Real T, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real SpinerEOSDependsRhoSie::BulkModulusFromDensityTemperature( + const Real rho, const Real T, Indexer_t &&lambda) const { return interpRhoT_(rho, T, dependsRhoT_.bMod, lambda); } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoSie::BulkModulusFromDensityInternalEnergy(const Real rho, - const Real sie, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real +SpinerEOSDependsRhoSie::BulkModulusFromDensityInternalEnergy(const Real rho, + const Real sie, + Indexer_t &&lambda) const { return interpRhoSie_(rho, sie, dependsRhoSie_.bMod, lambda); } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoSie::GruneisenParamFromDensityTemperature(const Real rho, - const Real T, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real +SpinerEOSDependsRhoSie::GruneisenParamFromDensityTemperature(const Real rho, const Real T, + Indexer_t &&lambda) const { const Real dpde = interpRhoT_(rho, T, dependsRhoT_.dPdE, lambda); return dpde / rho; } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoSie::GruneisenParamFromDensityInternalEnergy(const Real rho, - const Real sie, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real +SpinerEOSDependsRhoSie::GruneisenParamFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda) const { const Real lRho = toLog_(rho, lRhoOffset_); const Real lE = toLog_(sie, lEOffset_); const Real dpde = dependsRhoSie_.dPdE.interpToReal(lRho, lE); return dpde / rho; } -PORTABLE_INLINE_FUNCTION -void SpinerEOSDependsRhoSie::DensityEnergyFromPressureTemperature(const Real press, - const Real temp, - Real *lambda, Real &rho, - Real &sie) const { +template +PORTABLE_INLINE_FUNCTION void +SpinerEOSDependsRhoSie::DensityEnergyFromPressureTemperature(const Real press, + const Real temp, + Indexer_t &&lambda, + Real &rho, Real &sie) const { Real lT = toLog_(temp, lTOffset_); Real lRho = lRhoFromPlT_(press, lT, lambda); rho = fromLog_(lRho, lRhoOffset_); sie = sie_.interpToReal(lRho, lT); } -PORTABLE_INLINE_FUNCTION -void SpinerEOSDependsRhoSie::FillEos(Real &rho, Real &temp, Real &energy, Real &press, - Real &cv, Real &bmod, const unsigned long output, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION void +SpinerEOSDependsRhoSie::FillEos(Real &rho, Real &temp, Real &energy, Real &press, + Real &cv, Real &bmod, const unsigned long output, + Indexer_t &&lambda) const { Real lRho, lT, lE; if (output == thermalqs::none) { UNDEFINED_ERROR; @@ -1816,7 +1847,7 @@ void SpinerEOSDependsRhoSie::FillEos(Real &rho, Real &temp, Real &energy, Real & } } else { lRho = toLog_(rho, lRhoOffset_); - if (lambda != nullptr) *lambda = lRho; + if (!variadic_utils::is_nullptr(lambda)) lambda[0] = lRho; } if (output & thermalqs::temperature) { lE = toLog_(energy, lEOffset_); @@ -1846,11 +1877,10 @@ void SpinerEOSDependsRhoSie::FillEos(Real &rho, Real &temp, Real &energy, Real & } } -PORTABLE_INLINE_FUNCTION -void SpinerEOSDependsRhoSie::ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, - Real &press, Real &cv, Real &bmod, - Real &dpde, Real &dvdt, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION void SpinerEOSDependsRhoSie::ValuesAtReferenceState( + Real &rho, Real &temp, Real &sie, Real &press, Real &cv, Real &bmod, Real &dpde, + Real &dvdt, Indexer_t &&lambda) const { rho = rhoNormal_; temp = TNormal_; sie = sieNormal_; @@ -1861,31 +1891,31 @@ void SpinerEOSDependsRhoSie::ValuesAtReferenceState(Real &rho, Real &temp, Real dvdt = dVdTNormal_; } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoSie::interpRhoT_(const Real rho, const Real T, const DataBox &db, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real SpinerEOSDependsRhoSie::interpRhoT_( + const Real rho, const Real T, const DataBox &db, Indexer_t &&lambda) const { const Real lRho = toLog_(rho, lRhoOffset_); const Real lT = toLog_(T, lTOffset_); - if (lambda != nullptr) { - *lambda = lRho; + if (!variadic_utils::is_nullptr(lambda)) { + lambda[0] = lRho; } return db.interpToReal(lRho, lT); } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoSie::interpRhoSie_(const Real rho, const Real sie, - const DataBox &db, Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real SpinerEOSDependsRhoSie::interpRhoSie_( + const Real rho, const Real sie, const DataBox &db, Indexer_t &&lambda) const { const Real lRho = toLog_(rho, lRhoOffset_); const Real lE = toLog_(sie, lEOffset_); - if (lambda != nullptr) { - *lambda = lRho; + if (!variadic_utils::is_nullptr(lambda)) { + lambda[0] = lRho; } return db.interpToReal(lRho, lE); } -PORTABLE_INLINE_FUNCTION -Real SpinerEOSDependsRhoSie::lRhoFromPlT_(const Real P, const Real lT, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real SpinerEOSDependsRhoSie::lRhoFromPlT_( + const Real P, const Real lT, Indexer_t &&lambda) const { const RootFinding1D::RootCounts *pcounts = (memoryStatus_ == DataStatus::OnDevice) ? nullptr : &counts; Real lRho; @@ -1899,8 +1929,9 @@ Real SpinerEOSDependsRhoSie::lRhoFromPlT_(const Real P, const Real lT, } } else { Real lRhoGuess = reproducible_ ? lRhoMin_ : 0.5 * (lRhoMin_ + lRhoMax_); - if (lambda != nullptr && lRhoMin_ <= *lambda && *lambda <= lRhoMax_) { - lRhoGuess = *lambda; + if (!variadic_utils::is_nullptr(lambda) && lRhoMin_ <= lambda[0] && + lambda[0] <= lRhoMax_) { + lRhoGuess = lambda[0]; } const callable_interp::l_interp PFunc(dependsRhoT_.P, lT); auto status = ROOT_FINDER(PFunc, P, lRhoGuess, lRhoMin_, lRhoMax_, robust::EPS(), @@ -1921,7 +1952,7 @@ Real SpinerEOSDependsRhoSie::lRhoFromPlT_(const Real P, const Real lT, lRho = reproducible_ ? lRhoMin_ : lRhoGuess; } } - if (lambda != nullptr) *lambda = lRho; + if (!variadic_utils::is_nullptr(lambda)) lambda[0] = lRho; return lRho; } diff --git a/singularity-eos/eos/eos_stellar_collapse.hpp b/singularity-eos/eos/eos_stellar_collapse.hpp index c08ffdfeda..b8aab80bb0 100644 --- a/singularity-eos/eos/eos_stellar_collapse.hpp +++ b/singularity-eos/eos/eos_stellar_collapse.hpp @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// © 2021-2023. Triad National Security, LLC. All rights reserved. This +// © 2021-2024. Triad National Security, LLC. All rights reserved. This // program was produced under U.S. Government contract 89233218CNA000001 // for Los Alamos National Laboratory (LANL), which is operated by Triad // National Security, LLC for the U.S. Department of Energy/National @@ -37,6 +37,7 @@ #include #include #include +#include #include // spiner @@ -97,63 +98,84 @@ class StellarCollapse : public EosBase { inline StellarCollapse GetOnDevice(); - PORTABLE_INLINE_FUNCTION - Real TemperatureFromDensityInternalEnergy(const Real rho, const Real sie, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real InternalEnergyFromDensityTemperature(const Real rho, const Real temperature, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real PressureFromDensityTemperature(const Real rho, const Real temperature, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real PressureFromDensityInternalEnergy(const Real rho, const Real sie, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real MinInternalEnergyFromDensity(const Real rho, Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real EntropyFromDensityTemperature(const Real rho, const Real temperature, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real EntropyFromDensityInternalEnergy(const Real rho, const Real sie, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real SpecificHeatFromDensityTemperature(const Real rho, const Real temperature, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real SpecificHeatFromDensityInternalEnergy(const Real rho, const Real sie, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real BulkModulusFromDensityTemperature(const Real rho, const Real temperature, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real BulkModulusFromDensityInternalEnergy(const Real rho, const Real sie, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real GruneisenParamFromDensityTemperature(const Real rho, const Real temperature, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - Real GruneisenParamFromDensityInternalEnergy(const Real rho, const Real sie, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - void DensityEnergyFromPressureTemperature(const Real press, const Real temp, - Real *lambda, Real &rho, Real &sie) const; + template + PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real InternalEnergyFromDensityTemperature( + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real + PressureFromDensityTemperature(const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real PressureFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real MinInternalEnergyFromDensity( + const Real rho, Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real + EntropyFromDensityTemperature(const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real EntropyFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityTemperature( + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityTemperature( + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityTemperature( + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityInternalEnergy( + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION void + DensityEnergyFromPressureTemperature(const Real press, const Real temp, + Indexer_t &&lambda, Real &rho, Real &sie) const; // Properties of an NSE EOS - PORTABLE_INLINE_FUNCTION - void MassFractionsFromDensityTemperature(const Real rho, const Real temperature, - Real &Xa, Real &Xh, Real &Xn, Real &Xp, - Real &Abar, Real &Zbar, - Real *lambda = nullptr) const; - - PORTABLE_INLINE_FUNCTION - void FillEos(Real &rho, Real &temp, Real &energy, Real &press, Real &cv, Real &bmod, - const unsigned long output, Real *lambda = nullptr) const; - - PORTABLE_INLINE_FUNCTION - void ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, - Real &bmod, Real &dpde, Real &dvdt, - Real *lambda = nullptr) const; + template + PORTABLE_INLINE_FUNCTION void MassFractionsFromDensityTemperature( + const Real rho, const Real temperature, Real &Xa, Real &Xh, Real &Xn, Real &Xp, + Real &Abar, Real &Zbar, Indexer_t &&lambda = static_cast(nullptr)) const; + + template + PORTABLE_INLINE_FUNCTION void ChemicalPotentialsFromDensityTemperature( + const Real rho, const Real temperature, Real &mu_e, Real &mu_n, Real &mu_p, + Real &muhat, Real &munu, Indexer_t &&lambda = static_cast(nullptr)) const; + + template + PORTABLE_INLINE_FUNCTION void + FillEos(Real &rho, Real &temp, Real &energy, Real &press, Real &cv, Real &bmod, + const unsigned long output, + Indexer_t &&lambda = static_cast(nullptr)) const; + + template + PORTABLE_INLINE_FUNCTION void + ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, + Real &bmod, Real &dpde, Real &dvdt, + Indexer_t &&lambda = static_cast(nullptr)) const; // Generic functions provided by the base class. These contain e.g. the vector // overloads that use the scalar versions declared here static constexpr unsigned long PreferredInput() { return _preferred_input; } @@ -230,8 +252,9 @@ class StellarCollapse : public EosBase { inline void computeColdAndHotCurves_(); inline void setNormalValues_(); - PORTABLE_FORCEINLINE_FUNCTION void checkLambda_(Real *lambda) const noexcept { - if (lambda == nullptr) { + template + PORTABLE_FORCEINLINE_FUNCTION void checkLambda_(Indexer_t &&lambda) const noexcept { + if (variadic_utils::is_nullptr(lambda)) { EOS_ERROR("StellarCollapse: lambda must contain Ye and 1 space for caching.\n"); } } @@ -283,20 +306,23 @@ class StellarCollapse : public EosBase { return toLog_(B, lBOffset_); } + template PORTABLE_INLINE_FUNCTION Real lTFromlRhoSie_(const Real lRho, const Real sie, - Real *lambda) const noexcept; + Indexer_t &&lambda) const noexcept; + template PORTABLE_INLINE_FUNCTION __attribute__((always_inline)) void - getLogsFromRhoT_(const Real rho, const Real temp, Real *lambda, Real &lRho, Real &lT, - Real &Ye) const noexcept { + getLogsFromRhoT_(const Real rho, const Real temp, Indexer_t &&lambda, Real &lRho, + Real &lT, Real &Ye) const noexcept { checkLambda_(lambda); lRho = lRho_(rho); lT = lT_(temp); Ye = lambda[Lambda::Ye]; lambda[Lambda::lT] = lT; } + template PORTABLE_INLINE_FUNCTION __attribute__((always_inline)) void - getLogsFromRhoSie_(const Real rho, const Real sie, Real *lambda, Real &lRho, Real &lT, - Real &Ye) const noexcept { + getLogsFromRhoSie_(const Real rho, const Real sie, Indexer_t &&lambda, Real &lRho, + Real &lT, Real &Ye) const noexcept { lRho = lRho_(rho); lT = lTFromlRhoSie_(lRho, sie, lambda); Ye = lambda[Lambda::Ye]; @@ -315,7 +341,12 @@ class StellarCollapse : public EosBase { DataBox Xp_; // mass fraction of protons DataBox Abar_; // Average atomic mass DataBox Zbar_; // Average atomic number - // DataBox gamma_; // polytropic index. dlog(P)/dlog(rho). + DataBox mu_e_; // chemical potential of electrons + DataBox mu_n_; // chemical potential of neutrons + DataBox mu_p_; // chemical potential of protons + DataBox muhat_; // mu_n-mu_p + DataBox munu_; // chemical potential of neutrinos + // Spiner::DataBox gamma_; // polytropic index. dlog(P)/dlog(rho). // dTdRho_, dTdE_, dEdRho_, dEdT_; // Bounds of dependent variables. Needed for root finding. @@ -405,6 +436,11 @@ inline void StellarCollapse::Save(const std::string &filename) { status += lBMod_.saveHDF(file, "logbulkmodulus"); status += eCold_.saveHDF(file, "ecold"); status += eHot_.saveHDF(file, "ehot"); + status += mu_e_.saveHDF(file, "mu_e"); + status += mu_n_.saveHDF(file, "mu_n"); + status += mu_p_.saveHDF(file, "mu_p"); + status += muhat_.saveHDF(file, "muhat"); + status += munu_.saveHDF(file, "munu"); status += H5Fclose(file); if (status != H5_SUCCESS) { @@ -429,6 +465,11 @@ inline StellarCollapse StellarCollapse::GetOnDevice() { other.lBMod_ = Spiner::getOnDeviceDataBox(lBMod_); other.eCold_ = Spiner::getOnDeviceDataBox(eCold_); other.eHot_ = Spiner::getOnDeviceDataBox(eHot_); + other.mu_e_ = Spiner::getOnDeviceDataBox(mu_e_); + other.mu_n_ = Spiner::getOnDeviceDataBox(mu_n_); + other.mu_p_ = Spiner::getOnDeviceDataBox(mu_p_); + other.muhat_ = Spiner::getOnDeviceDataBox(muhat_); + other.munu_ = Spiner::getOnDeviceDataBox(munu_); other.memoryStatus_ = DataStatus::OnDevice; other.numRho_ = numRho_; other.numT_ = numT_; @@ -467,94 +508,94 @@ inline void StellarCollapse::Finalize() { lBMod_.finalize(); eCold_.finalize(); eHot_.finalize(); + mu_e_.finalize(); + mu_n_.finalize(); + mu_p_.finalize(); + muhat_.finalize(); + munu_.finalize(); memoryStatus_ = DataStatus::Deallocated; } -PORTABLE_INLINE_FUNCTION -Real StellarCollapse::TemperatureFromDensityInternalEnergy(const Real rho, const Real sie, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real StellarCollapse::TemperatureFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda) const { const Real lRho = lRho_(rho); const Real lT = lTFromlRhoSie_(lRho, sie, lambda); return T_(lT); } -PORTABLE_INLINE_FUNCTION -Real StellarCollapse::InternalEnergyFromDensityTemperature(const Real rho, - const Real temp, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real StellarCollapse::InternalEnergyFromDensityTemperature( + const Real rho, const Real temp, Indexer_t &&lambda) const { Real lRho, lT, Ye; getLogsFromRhoT_(rho, temp, lambda, lRho, lT, Ye); const Real lE = lE_.interpToReal(Ye, lT, lRho); return le2e_(lE); } -PORTABLE_INLINE_FUNCTION -Real StellarCollapse::PressureFromDensityTemperature(const Real rho, - const Real temperature, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real StellarCollapse::PressureFromDensityTemperature( + const Real rho, const Real temperature, Indexer_t &&lambda) const { Real lRho, lT, Ye; getLogsFromRhoT_(rho, temperature, lambda, lRho, lT, Ye); const Real lP = lP_.interpToReal(Ye, lT, lRho); return lP2P_(lP); } -PORTABLE_INLINE_FUNCTION -Real StellarCollapse::PressureFromDensityInternalEnergy(const Real rho, const Real sie, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real StellarCollapse::PressureFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda) const { Real lRho, lT, Ye; getLogsFromRhoSie_(rho, sie, lambda, lRho, lT, Ye); const Real lP = lP_.interpToReal(Ye, lT, lRho); return lP2P_(lP); } -PORTABLE_INLINE_FUNCTION -Real StellarCollapse::MinInternalEnergyFromDensity(const Real rho, Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real +StellarCollapse::MinInternalEnergyFromDensity(const Real rho, Indexer_t &&lambda) const { MinInternalEnergyIsNotEnabled("Stellar Collapse"); return 0.0; } -PORTABLE_INLINE_FUNCTION -Real StellarCollapse::EntropyFromDensityTemperature(const Real rho, - const Real temperature, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real StellarCollapse::EntropyFromDensityTemperature( + const Real rho, const Real temperature, Indexer_t &&lambda) const { Real lRho, lT, Ye; getLogsFromRhoT_(rho, temperature, lambda, lRho, lT, Ye); const Real entropy = entropy_.interpToReal(Ye, lT, lRho); return (entropy > robust::EPS() ? entropy : robust::EPS()); } -PORTABLE_INLINE_FUNCTION -Real StellarCollapse::EntropyFromDensityInternalEnergy(const Real rho, const Real sie, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real StellarCollapse::EntropyFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda) const { Real lRho, lT, Ye; getLogsFromRhoSie_(rho, sie, lambda, lRho, lT, Ye); const Real entropy = entropy_.interpToReal(Ye, lT, lRho); return (entropy > robust::EPS() ? entropy : robust::EPS()); } -PORTABLE_INLINE_FUNCTION -Real StellarCollapse::SpecificHeatFromDensityTemperature(const Real rho, - const Real temperature, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real StellarCollapse::SpecificHeatFromDensityTemperature( + const Real rho, const Real temperature, Indexer_t &&lambda) const { Real lRho, lT, Ye; getLogsFromRhoT_(rho, temperature, lambda, lRho, lT, Ye); const Real Cv = dEdT_.interpToReal(Ye, lT, lRho); return (Cv > robust::EPS() ? Cv : robust::EPS()); } -PORTABLE_INLINE_FUNCTION -Real StellarCollapse::SpecificHeatFromDensityInternalEnergy(const Real rho, - const Real sie, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real StellarCollapse::SpecificHeatFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda) const { Real lRho, lT, Ye; getLogsFromRhoSie_(rho, sie, lambda, lRho, lT, Ye); const Real Cv = dEdT_.interpToReal(Ye, lT, lRho); return (Cv > robust::EPS() ? Cv : robust::EPS()); } -PORTABLE_INLINE_FUNCTION -Real StellarCollapse::BulkModulusFromDensityTemperature(const Real rho, - const Real temperature, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real StellarCollapse::BulkModulusFromDensityTemperature( + const Real rho, const Real temperature, Indexer_t &&lambda) const { Real lRho, lT, Ye; getLogsFromRhoT_(rho, temperature, lambda, lRho, lT, Ye); const Real lbmod = lBMod_.interpToReal(Ye, lT, lRho); @@ -562,10 +603,9 @@ Real StellarCollapse::BulkModulusFromDensityTemperature(const Real rho, return bMod > robust::EPS() ? bMod : robust::EPS(); } -PORTABLE_INLINE_FUNCTION -Real StellarCollapse::GruneisenParamFromDensityTemperature(const Real rho, - const Real temp, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real StellarCollapse::GruneisenParamFromDensityTemperature( + const Real rho, const Real temp, Indexer_t &&lambda) const { Real lRho, lT, Ye; getLogsFromRhoT_(rho, temp, lambda, lRho, lT, Ye); const Real dpde = dPdE_.interpToReal(Ye, lT, lRho); @@ -573,9 +613,9 @@ Real StellarCollapse::GruneisenParamFromDensityTemperature(const Real rho, return gm1; } -PORTABLE_INLINE_FUNCTION -Real StellarCollapse::BulkModulusFromDensityInternalEnergy(const Real rho, const Real sie, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real StellarCollapse::BulkModulusFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda) const { Real lRho, lT, Ye; getLogsFromRhoSie_(rho, sie, lambda, lRho, lT, Ye); const Real lbmod = lBMod_.interpToReal(Ye, lT, lRho); @@ -583,10 +623,9 @@ Real StellarCollapse::BulkModulusFromDensityInternalEnergy(const Real rho, const return bMod; } -PORTABLE_INLINE_FUNCTION -Real StellarCollapse::GruneisenParamFromDensityInternalEnergy(const Real rho, - const Real sie, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION Real StellarCollapse::GruneisenParamFromDensityInternalEnergy( + const Real rho, const Real sie, Indexer_t &&lambda) const { Real lRho, lT, Ye; getLogsFromRhoSie_(rho, sie, lambda, lRho, lT, Ye); const Real dpde = dPdE_.interpToReal(Ye, lT, lRho); @@ -595,17 +634,16 @@ Real StellarCollapse::GruneisenParamFromDensityInternalEnergy(const Real rho, } // TODO(JMM): Fill in this stub if we ever use this EOS in a PTE code. -PORTABLE_INLINE_FUNCTION -void StellarCollapse::DensityEnergyFromPressureTemperature(const Real press, - const Real temp, Real *lambda, - Real &rho, Real &sie) const { +template +PORTABLE_INLINE_FUNCTION void StellarCollapse::DensityEnergyFromPressureTemperature( + const Real press, const Real temp, Indexer_t &&lambda, Real &rho, Real &sie) const { EOS_ERROR("StellarCollapse::DensityEnergyFromPRessureTemperature is a stub"); } -PORTABLE_INLINE_FUNCTION -void StellarCollapse::MassFractionsFromDensityTemperature( +template +PORTABLE_INLINE_FUNCTION void StellarCollapse::MassFractionsFromDensityTemperature( const Real rho, const Real temperature, Real &Xa, Real &Xh, Real &Xn, Real &Xp, - Real &Abar, Real &Zbar, Real *lambda) const { + Real &Abar, Real &Zbar, Indexer_t &&lambda) const { Real lRho, lT, Ye; getLogsFromRhoT_(rho, temperature, lambda, lRho, lT, Ye); Xa = Xa_.interpToReal(Ye, lT, lRho); @@ -616,10 +654,24 @@ void StellarCollapse::MassFractionsFromDensityTemperature( Zbar = Zbar_.interpToReal(Ye, lT, lRho); } -PORTABLE_INLINE_FUNCTION -void StellarCollapse::FillEos(Real &rho, Real &temp, Real &energy, Real &press, Real &cv, - Real &bmod, const unsigned long output, - Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION void StellarCollapse::ChemicalPotentialsFromDensityTemperature( + const Real rho, const Real temperature, Real &mu_e, Real &mu_n, Real &mu_p, + Real &muhat, Real &munu, Indexer_t &&lambda) const { + Real lRho, lT, Ye; + getLogsFromRhoT_(rho, temperature, lambda, lRho, lT, Ye); + mu_e = mu_e_.interpToReal(Ye, lT, lRho); + mu_n = mu_n_.interpToReal(Ye, lT, lRho); + mu_p = mu_p_.interpToReal(Ye, lT, lRho); + muhat = muhat_.interpToReal(Ye, lT, lRho); + munu = munu_.interpToReal(Ye, lT, lRho); +} + +template +PORTABLE_INLINE_FUNCTION void +StellarCollapse::FillEos(Real &rho, Real &temp, Real &energy, Real &press, Real &cv, + Real &bmod, const unsigned long output, + Indexer_t &&lambda) const { Real lRho, lT, Ye; const unsigned long input = ~output; if (output == thermalqs::none) { @@ -653,10 +705,11 @@ void StellarCollapse::FillEos(Real &rho, Real &temp, Real &energy, Real &press, } } -PORTABLE_INLINE_FUNCTION -void StellarCollapse::ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, - Real &press, Real &cv, Real &bmod, - Real &dpde, Real &dvdt, Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION void +StellarCollapse::ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, + Real &cv, Real &bmod, Real &dpde, Real &dvdt, + Indexer_t &&lambda) const { rho = rhoNormal_; temp = TNormal_; sie = sieNormal_; @@ -696,6 +749,11 @@ inline void StellarCollapse::LoadFromSP5File_(const std::string &filename) { status += lBMod_.loadHDF(file, "logbulkmodulus"); status += eCold_.loadHDF(file, "ecold"); status += eHot_.loadHDF(file, "ehot"); + status += mu_e_.loadHDF(file, "mu_e"); + status += mu_n_.loadHDF(file, "mu_n"); + status += mu_p_.loadHDF(file, "mu_p"); + status += muhat_.loadHDF(file, "muhat"); + status += munu_.loadHDF(file, "munu"); status += H5Fclose(file); if (status != H5_SUCCESS) { @@ -776,6 +834,11 @@ inline void StellarCollapse::LoadFromStellarCollapseFile_(const std::string &fil readSCDset_(file_id, "Xp", Ye_grid, lT_grid, lRho_grid, Xp_); readSCDset_(file_id, "Abar", Ye_grid, lT_grid, lRho_grid, Abar_); readSCDset_(file_id, "Zbar", Ye_grid, lT_grid, lRho_grid, Zbar_); + readSCDset_(file_id, "mu_e", Ye_grid, lT_grid, lRho_grid, mu_e_); + readSCDset_(file_id, "mu_n", Ye_grid, lT_grid, lRho_grid, mu_n_); + readSCDset_(file_id, "mu_p", Ye_grid, lT_grid, lRho_grid, mu_p_); + readSCDset_(file_id, "muhat", Ye_grid, lT_grid, lRho_grid, muhat_); + readSCDset_(file_id, "munu", Ye_grid, lT_grid, lRho_grid, munu_); H5Fclose(file_id); // ----------------------------------------------------------------------- @@ -1064,9 +1127,9 @@ inline void StellarCollapse::setNormalValues_() { dVdTNormal_ = dPdENormal_ * CvNormal_ / (rhoNormal_ * rhoNormal_ * dPdR); } -PORTABLE_INLINE_FUNCTION -Real StellarCollapse::lTFromlRhoSie_(const Real lRho, const Real sie, - Real *lambda) const noexcept { +template +PORTABLE_INLINE_FUNCTION Real StellarCollapse::lTFromlRhoSie_( + const Real lRho, const Real sie, Indexer_t &&lambda) const noexcept { checkLambda_(lambda); RootFinding1D::Status status = RootFinding1D::Status::SUCCESS; using RootFinding1D::regula_falsi; diff --git a/singularity-eos/eos/eos_stiff.hpp b/singularity-eos/eos/eos_stiff.hpp index c60f2f60a4..d0ca49e096 100644 --- a/singularity-eos/eos/eos_stiff.hpp +++ b/singularity-eos/eos/eos_stiff.hpp @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// © 2021-2023. Triad National Security, LLC. All rights reserved. This +// © 2021-2024. Triad National Security, LLC. All rights reserved. This // program was produced under U.S. Government contract 89233218CNA000001 // for Los Alamos National Laboratory (LANL), which is operated by Triad // National Security, LLC for the U.S. Department of Energy/National @@ -57,77 +57,105 @@ class StiffGas : public EosBase { checkParams(); } StiffGas GetOnDevice() { return *this; } + template PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { return std::max(robust::SMALL(), robust::ratio(rho * (sie - _qq) - _Pinf, rho * _Cv)); } PORTABLE_INLINE_FUNCTION void checkParams() const { PORTABLE_ALWAYS_REQUIRE(_Cv >= 0, "Heat capacity must be positive"); PORTABLE_ALWAYS_REQUIRE(_gm1 >= 0, "Gruneisen parameter must be positive"); } + template PORTABLE_INLINE_FUNCTION Real InternalEnergyFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { return std::max(_qq, robust::ratio(rho * _Cv * temperature + _Pinf, rho) + _qq); } + template PORTABLE_INLINE_FUNCTION Real PressureFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { return std::max(-_Pinf, _gm1 * rho * _Cv * temperature - _Pinf); } + template PORTABLE_INLINE_FUNCTION Real PressureFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { return std::max(-_Pinf, _gm1 * rho * (sie - _qq) - (_gm1 + 1.0) * _Pinf); } - PORTABLE_INLINE_FUNCTION Real - MinInternalEnergyFromDensity(const Real rho, Real *lambda = nullptr) const { + template + PORTABLE_INLINE_FUNCTION Real MinInternalEnergyFromDensity( + const Real rho, Indexer_t &&lambda = static_cast(nullptr)) const { MinInternalEnergyIsNotEnabled("StiffGas"); return 0.0; }; - PORTABLE_INLINE_FUNCTION Real EntropyFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + template + PORTABLE_INLINE_FUNCTION Real + EntropyFromDensityTemperature(const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { return _Cv * std::log(robust::ratio(temperature, _T0) + robust::SMALL()) + _gm1 * _Cv * std::log(robust::ratio(_rho0, rho) + robust::SMALL()) + _qp; } + template PORTABLE_INLINE_FUNCTION Real EntropyFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { const Real vol = robust::ratio(1.0, rho); return _Cv * std::log(robust::ratio((sie - _qq - _Pinf * vol), (_sie0 - _qq - _Pinf * _vol0)) + robust::SMALL()) + _Cv * _gm1 * std::log(robust::ratio(vol, _vol0) + robust::SMALL()) + _qp; } + template PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { return _Cv; } + template PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { return _Cv; } + template PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { return std::max(robust::SMALL(), _gm1 * (_gm1 + 1.0) * rho * _Cv * temperature); } + template PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { return std::max(robust::SMALL(), _gm1 * (_gm1 + 1.0) * (rho * (sie - _qq) - _Pinf)); } + template PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityTemperature( - const Real rho, const Real temperature, Real *lambda = nullptr) const { + const Real rho, const Real temperature, + Indexer_t &&lambda = static_cast(nullptr)) const { return _gm1; } + template PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityInternalEnergy( - const Real rho, const Real sie, Real *lambda = nullptr) const { + const Real rho, const Real sie, + Indexer_t &&lambda = static_cast(nullptr)) const { return _gm1; } - PORTABLE_INLINE_FUNCTION void FillEos(Real &rho, Real &temp, Real &energy, Real &press, - Real &cv, Real &bmod, const unsigned long output, - Real *lambda = nullptr) const; - PORTABLE_INLINE_FUNCTION - void ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, - Real &bmod, Real &dpde, Real &dvdt, - Real *lambda = nullptr) const { + template + PORTABLE_INLINE_FUNCTION void + FillEos(Real &rho, Real &temp, Real &energy, Real &press, Real &cv, Real &bmod, + const unsigned long output, + Indexer_t &&lambda = static_cast(nullptr)) const; + template + PORTABLE_INLINE_FUNCTION void + ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, + Real &bmod, Real &dpde, Real &dvdt, + Indexer_t &&lambda = static_cast(nullptr)) const { // use STP: 1 atmosphere, room temperature rho = _rho0; temp = _T0; @@ -152,9 +180,10 @@ class StiffGas : public EosBase { "%g\n", _gm1 + 1.0, _Cv, _Pinf, _qq); } + template PORTABLE_INLINE_FUNCTION void - DensityEnergyFromPressureTemperature(const Real press, const Real temp, Real *lambda, - Real &rho, Real &sie) const { + DensityEnergyFromPressureTemperature(const Real press, const Real temp, + Indexer_t &&lambda, Real &rho, Real &sie) const { sie = std::max( _qq, robust::ratio(press + (_gm1 + 1.0) * _Pinf, press + _Pinf) * _Cv * temp + _qq); @@ -176,9 +205,10 @@ class StiffGas : public EosBase { thermalqs::density | thermalqs::specific_internal_energy; }; -PORTABLE_INLINE_FUNCTION -void StiffGas::FillEos(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, - Real &bmod, const unsigned long output, Real *lambda) const { +template +PORTABLE_INLINE_FUNCTION void +StiffGas::FillEos(Real &rho, Real &temp, Real &sie, Real &press, Real &cv, Real &bmod, + const unsigned long output, Indexer_t &&lambda) const { if (output & thermalqs::density && output & thermalqs::specific_internal_energy) { if (output & thermalqs::pressure || output & thermalqs::temperature) { UNDEFINED_ERROR; diff --git a/singularity-eos/eos/eos_type_lists.hpp b/singularity-eos/eos/eos_type_lists.hpp new file mode 100644 index 0000000000..c0429fa77e --- /dev/null +++ b/singularity-eos/eos/eos_type_lists.hpp @@ -0,0 +1,130 @@ +//------------------------------------------------------------------------------ +// © 2021-2024. Triad National Security, LLC. All rights reserved. This +// program was produced under U.S. Government contract 89233218CNA000001 +// for Los Alamos National Laboratory (LANL), which is operated by Triad +// National Security, LLC for the U.S. Department of Energy/National +// Nuclear Security Administration. All rights in the program are +// reserved by Triad National Security, LLC, and the U.S. Department of +// Energy/National Nuclear Security Administration. The Government is +// granted for itself and others acting on its behalf a nonexclusive, +// paid-up, irrevocable worldwide license in this material to reproduce, +// prepare derivative works, distribute copies to the public, perform +// publicly and display publicly, and to permit others to do so. +//------------------------------------------------------------------------------ + +#ifndef _SINGULARITY_EOS_EOS_EOS_TYPE_LISTS_HPP_ +#define _SINGULARITY_EOS_EOS_EOS_TYPE_LISTS_HPP_ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// Base stuff +#include +#include +#include + +// EOS models +#include + +namespace singularity { + +// recreate variadic list +template +using tl = singularity::variadic_utils::type_list; + +template