From 00661cfdd2aed260a24ed3b1b3a08c3fc617cdd0 Mon Sep 17 00:00:00 2001 From: Luke Shingles Date: Sat, 21 Oct 2023 10:35:10 +0200 Subject: [PATCH] v2023.10 (#40) New features - New 2D Cylindrical propagation grid option (for direct mapping of 2D input models) - Added test models for various combinations of 1D/2D input models and 1D/2D/3D propagation grids. - EXPERIMENTAL: Allow hybrid NLTE mode with some elements in full Non-LTE and other elements in either LTE or photoionisation equilibrium (classic quasi NLTE). Set with artisoptions.h LEVEL_IS_NLTE() - EXPERIMENTAL: Enforce Saha ionisation balance (allowing NLTE level pops) with artisoptions.h FORCE_SAHA_ION_BALANCE() function. - EXPERIMENTAL: FORCE_SPHERICAL_ESCAPE_SURFACE to remove the corners of a 2D or 3D model to create a spherical escape surface (allowing for increased velocity per axis cutoff). Cells with v_r_mid > vmax are set to empty, and packets found in cells with vel_r_inner > vmax are set to escaped. Fixes - Fix virtual packets (storage of bound-free departure coeff in cell history had introduced a dependence on the not-updated cell history) - Fix for bug in 1D spherical grid mode that caused a some packets to get out of their correct cells. Now ready for production use. Mapping of 1D and 2D models to a 3D Cartesian grid is still possible, but no longer recommended for new models. - Fix adiabatic cooling rate with NLTE populations on, replacing nnetot (free and bound electron density) with nntot (ion plus free electron density). No change to W7 nebular spectrum. --- .clang-tidy | 5 +- .github/workflows/ci-checks.yml | 55 +- .github/workflows/ci.yml | 54 +- .pre-commit-config.yaml | 2 +- CMakeLists.txt | 12 +- Makefile | 34 +- README.old | 4 +- artisoptions_christinenonthermal.h | 11 +- artisoptions_classic.h | 11 +- artisoptions_doc.md | 18 +- artisoptions_kilonova_lte.h | 13 +- artisoptions_nltenebular.h | 11 +- artisoptions_nltewithoutnonthermal.h | 11 +- atomic.cc | 60 +- atomic.h | 7 +- boundary.cc | 372 ----- boundary.h | 17 - constants.h | 12 +- decay.cc | 704 +++++---- decay.h | 11 +- exspec.cc | 363 ++--- gammapkt.cc | 284 ++-- globals.cc | 67 +- globals.h | 100 +- grid.cc | 1367 +++++++++++------ grid.h | 50 +- input.cc | 527 +++---- input.h | 12 +- kpkt.cc | 354 ++--- kpkt.h | 4 +- light_curve.cc | 28 +- light_curve.h | 8 +- ltepop.cc | 654 ++++---- ltepop.h | 14 +- macroatom.cc | 98 +- macroatom.h | 2 +- nltepop.cc | 632 +------- nltepop.h | 1 - nonthermal.cc | 142 +- packet.cc | 40 +- packet.h | 68 +- radfield.cc | 345 ++--- radfield.h | 7 +- ratecoeff.cc | 316 ++-- ratecoeff.h | 6 + rpkt.cc | 839 +++------- rpkt.h | 30 +- scripts/artis-juwels.sh | 5 +- scripts/artis-virgo-submit.sh | 2 +- scripts/exspec-after.sh | 2 +- scripts/exspec-gzip-juwels.sh | 4 +- sn3d.cc | 296 ++-- sn3d.h | 92 +- spectrum.cc | 289 ++-- spectrum.h | 31 +- stats.cc | 17 +- stats.h | 1 - .../abundances.txt | 0 .../compositiondata.txt | 0 .../input-newrun.txt | 4 +- .../input-resume.txt | 4 +- .../model.txt | 0 .../results_md5_final.txt | 25 + .../results_md5_job0.txt | 21 + .../syn_dir.txt | 0 .../classicmode_1d_3dgrid_inputfiles/vpkt.txt | 14 + .../input-newrun.txt | 4 +- .../input-resume.txt | 4 +- .../results_md5_final.txt | 1036 ++++++------- .../results_md5_job0.txt | 22 +- .../results_md5_final.txt | 23 - .../results_md5_job0.txt | 19 - tests/classicmode_inputfiles/vpkt.txt | 14 - .../results_md5_final.txt | 18 + .../results_md5_job0.txt | 17 + .../abundances.txt | 0 .../compositiondata.txt | 0 .../gridcontributions.txt.xz | Bin .../input-newrun.txt | 4 +- .../input-resume.txt | 4 +- .../model.txt.xz | Bin .../results_md5_final.txt | 18 + .../results_md5_job0.txt | 17 + .../syn_dir.txt | 0 .../results_md5_final.txt | 320 ++++ .../results_md5_job0.txt | 14 + .../abundances.txt.xz | Bin 0 -> 48296 bytes .../compositiondata.txt | 13 + .../gridcontributions.txt.xz | Bin 0 -> 52632 bytes .../input-newrun.txt | 24 + .../input-resume.txt | 24 + .../model.txt.xz | Bin 0 -> 655352 bytes .../results_md5_final.txt | 320 ++++ .../results_md5_job0.txt | 14 + .../syn_dir.txt | 0 .../kilonova_inputfiles/results_md5_final.txt | 18 - .../kilonova_inputfiles/results_md5_job0.txt | 17 - .../abundances.txt | 0 .../input-newrun.txt | 4 +- .../input-resume.txt | 4 +- .../model.txt | 0 .../recombrates.txt | 0 .../results_md5_final.txt | 20 + .../results_md5_job0.txt | 19 + .../syn_dir.txt | 1 + .../results_md5_final.txt | 20 - .../results_md5_job0.txt | 19 - tests/setup_classicmode.sh | 25 - tests/setup_classicmode_1d_3dgrid.sh | 35 + tests/setup_classicmode_3d.sh | 29 +- ...ilonova.sh => setup_kilonova_1d_1dgrid.sh} | 22 +- tests/setup_kilonova_1d_3dgrid.sh | 39 + tests/setup_kilonova_2d_2dgrid.sh | 37 + tests/setup_kilonova_2d_3dgrid.sh | 37 + ...e.sh => setup_nebularonezone_1d_3dgrid.sh} | 18 +- thermalbalance.cc | 37 +- update_grid.cc | 792 +++------- update_grid.h | 3 - update_packets.cc | 31 +- vectors.cc | 8 +- vectors.h | 70 +- vpkt.cc | 1221 +++++++-------- vpkt.h | 55 +- 123 files changed, 6304 insertions(+), 6795 deletions(-) delete mode 100644 boundary.cc delete mode 100644 boundary.h rename tests/{classicmode_inputfiles => classicmode_1d_3dgrid_inputfiles}/abundances.txt (100%) rename tests/{classicmode_inputfiles => classicmode_1d_3dgrid_inputfiles}/compositiondata.txt (100%) rename tests/{classicmode_inputfiles => classicmode_1d_3dgrid_inputfiles}/input-newrun.txt (92%) rename tests/{classicmode_inputfiles => classicmode_1d_3dgrid_inputfiles}/input-resume.txt (92%) rename tests/{classicmode_inputfiles => classicmode_1d_3dgrid_inputfiles}/model.txt (100%) create mode 100644 tests/classicmode_1d_3dgrid_inputfiles/results_md5_final.txt create mode 100644 tests/classicmode_1d_3dgrid_inputfiles/results_md5_job0.txt rename tests/{classicmode_inputfiles => classicmode_1d_3dgrid_inputfiles}/syn_dir.txt (100%) create mode 100644 tests/classicmode_1d_3dgrid_inputfiles/vpkt.txt delete mode 100644 tests/classicmode_inputfiles/results_md5_final.txt delete mode 100644 tests/classicmode_inputfiles/results_md5_job0.txt delete mode 100644 tests/classicmode_inputfiles/vpkt.txt create mode 100644 tests/kilonova_1d_1dgrid_inputfiles/results_md5_final.txt create mode 100644 tests/kilonova_1d_1dgrid_inputfiles/results_md5_job0.txt rename tests/{kilonova_inputfiles => kilonova_1d_3dgrid_inputfiles}/abundances.txt (100%) rename tests/{kilonova_inputfiles => kilonova_1d_3dgrid_inputfiles}/compositiondata.txt (100%) rename tests/{kilonova_inputfiles => kilonova_1d_3dgrid_inputfiles}/gridcontributions.txt.xz (100%) rename tests/{kilonova_inputfiles => kilonova_1d_3dgrid_inputfiles}/input-newrun.txt (92%) rename tests/{kilonova_inputfiles => kilonova_1d_3dgrid_inputfiles}/input-resume.txt (92%) rename tests/{kilonova_inputfiles => kilonova_1d_3dgrid_inputfiles}/model.txt.xz (100%) create mode 100644 tests/kilonova_1d_3dgrid_inputfiles/results_md5_final.txt create mode 100644 tests/kilonova_1d_3dgrid_inputfiles/results_md5_job0.txt rename tests/{kilonova_inputfiles => kilonova_1d_3dgrid_inputfiles}/syn_dir.txt (100%) create mode 100644 tests/kilonova_2d_2dgrid_inputfiles/results_md5_final.txt create mode 100644 tests/kilonova_2d_2dgrid_inputfiles/results_md5_job0.txt create mode 100644 tests/kilonova_2d_3dgrid_inputfiles/abundances.txt.xz create mode 100644 tests/kilonova_2d_3dgrid_inputfiles/compositiondata.txt create mode 100644 tests/kilonova_2d_3dgrid_inputfiles/gridcontributions.txt.xz create mode 100644 tests/kilonova_2d_3dgrid_inputfiles/input-newrun.txt create mode 100644 tests/kilonova_2d_3dgrid_inputfiles/input-resume.txt create mode 100644 tests/kilonova_2d_3dgrid_inputfiles/model.txt.xz create mode 100644 tests/kilonova_2d_3dgrid_inputfiles/results_md5_final.txt create mode 100644 tests/kilonova_2d_3dgrid_inputfiles/results_md5_job0.txt rename tests/{nebularonezone_inputfiles => kilonova_2d_3dgrid_inputfiles}/syn_dir.txt (100%) delete mode 100644 tests/kilonova_inputfiles/results_md5_final.txt delete mode 100644 tests/kilonova_inputfiles/results_md5_job0.txt rename tests/{nebularonezone_inputfiles => nebularonezone_1d_3dgrid_inputfiles}/abundances.txt (100%) rename tests/{nebularonezone_inputfiles => nebularonezone_1d_3dgrid_inputfiles}/input-newrun.txt (92%) rename tests/{nebularonezone_inputfiles => nebularonezone_1d_3dgrid_inputfiles}/input-resume.txt (92%) rename tests/{nebularonezone_inputfiles => nebularonezone_1d_3dgrid_inputfiles}/model.txt (100%) rename tests/{nebularonezone_inputfiles => nebularonezone_1d_3dgrid_inputfiles}/recombrates.txt (100%) create mode 100644 tests/nebularonezone_1d_3dgrid_inputfiles/results_md5_final.txt create mode 100644 tests/nebularonezone_1d_3dgrid_inputfiles/results_md5_job0.txt create mode 100644 tests/nebularonezone_1d_3dgrid_inputfiles/syn_dir.txt delete mode 100644 tests/nebularonezone_inputfiles/results_md5_final.txt delete mode 100644 tests/nebularonezone_inputfiles/results_md5_job0.txt delete mode 100755 tests/setup_classicmode.sh create mode 100755 tests/setup_classicmode_1d_3dgrid.sh rename tests/{setup_kilonova.sh => setup_kilonova_1d_1dgrid.sh} (57%) create mode 100755 tests/setup_kilonova_1d_3dgrid.sh create mode 100755 tests/setup_kilonova_2d_2dgrid.sh create mode 100755 tests/setup_kilonova_2d_3dgrid.sh rename tests/{setup_nebularonezone.sh => setup_nebularonezone_1d_3dgrid.sh} (57%) diff --git a/.clang-tidy b/.clang-tidy index e5635ab5b..4771bae80 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -14,6 +14,7 @@ Checks: > -llvmlibc-*, -cert-err33-c, -cert-err34-c, + -cert-err58-cpp, -cppcoreguidelines-avoid-magic-numbers, -cppcoreguidelines-avoid-non-const-global-variables, -cppcoreguidelines-no-malloc, @@ -21,6 +22,7 @@ Checks: > -cppcoreguidelines-pro-bounds-array-to-pointer-decay, -cppcoreguidelines-pro-bounds-constant-array-index, -cppcoreguidelines-pro-bounds-pointer-arithmetic, + -cppcoreguidelines-pro-type-reinterpret-cast, -cppcoreguidelines-pro-type-vararg, -clang-diagnostic-error, -fuchsia-*, @@ -32,6 +34,7 @@ Checks: > -hicpp-signed-bitwise, -misc-use-anonymous-namespace, -misc-no-recursion, + -misc-non-private-member-variables-in-classes, -readability-identifier-length, -readability-function-cognitive-complexity, -readability-magic-numbers, @@ -46,7 +49,7 @@ CheckOptions: - key: cppcoreguidelines-init-variables.MathHeader value: - key: cppcoreguidelines-narrowing-conversions.IgnoreConversionFromTypes - value: size_t;ptrdiff_t;size_type;difference_type;time_t + value: size_t;ptrdiff_t;size_type;difference_type;time_t;MPI_Aint;unsigned long - key: cppcoreguidelines-narrowing-conversions.WarnOnFloatingPointNarrowingConversion value: 'false' - key: cppcoreguidelines-narrowing-conversions.WarnOnIntegerToFloatingPointNarrowingConversion diff --git a/.github/workflows/ci-checks.yml b/.github/workflows/ci-checks.yml index 1f3ee5103..9041d052f 100644 --- a/.github/workflows/ci-checks.yml +++ b/.github/workflows/ci-checks.yml @@ -11,23 +11,26 @@ on: jobs: cppcheck: - runs-on: ubuntu-22.04 + runs-on: macos-latest steps: - uses: actions/checkout@v3 - name: install dependencies run: | - # git status - # sudo apt-get update - # sudo apt-get install libgsl-dev - # sudo apt install -y openmpi-bin libopenmpi-dev - sudo apt-get -y install cppcheck + brew update + brew install gsl openmpi cppcheck + cp artisoptions_nltenebular.h artisoptions.h - - name: run cppcheck + - name: run cppcheck and check for errors run: | - cp artisoptions_nltenebular.h artisoptions.h - cppcheck --force --language=c++ --std=c++20 . + cppcheck --version + cppcheck --force --error-exitcode=1 --language=c++ --std=c++20 --enable=warning,performance,portability . + + - name: show cppcheck style suggestions + run: | + cppcheck --version + cppcheck --force --language=c++ --std=c++20 --enable=style --suppress=knownConditionTrueFalse . clang-format: runs-on: ubuntu-22.04 @@ -45,12 +48,23 @@ jobs: runs-on: ubuntu-22.04 strategy: matrix: - compiler: [{name: gcc, ver: 11}, {name: gcc, ver: 12}, {name: clang, ver: 14}, {name: clang, ver: 15}] + compiler: [{name: gcc, ver: 11}, {name: gcc, ver: 12}, {name: gcc, ver: 13}, {name: clang, ver: 14}, {name: clang, ver: 15}] mpi: [ON, OFF] + openmp: [ON, OFF] artisoptionsfile: [artisoptions_classic.h, artisoptions_nltenebular.h] + exclude: + - compiler: {name: gcc, ver: 11} + openmp: ON + - compiler: {name: gcc, ver: 12} + openmp: ON + - compiler: {name: gcc, ver: 13} + openmp: ON + - compiler: {name: clang, ver: 15} + openmp: ON fail-fast: false - name: ${{ matrix.compiler.name }}-${{ matrix.compiler.ver }}${{ matrix.mpi == 'ON' && ' MPI' || ''}} ${{ matrix.artisoptionsfile }} + name: ${{ matrix.compiler.name }}-${{ matrix.compiler.ver }}${{ matrix.mpi == 'ON' && ' MPI' || ''}}${{ matrix.openmp == 'ON' && ' OpenMP' || ''}} + ${{ matrix.artisoptionsfile }} steps: - uses: actions/checkout@v3 @@ -61,20 +75,24 @@ jobs: # echo "count=$(python3 -c 'import psutil; print(int(psutil.cpu_count(logical=False)))')" >> $GITHUB_OUTPUT echo "count=$(python3 -c 'import multiprocessing; print(multiprocessing.cpu_count())')" >> $GITHUB_OUTPUT - - name: apt-get update + - name: apt update run: | + sudo add-apt-repository main + sudo add-apt-repository universe + sudo add-apt-repository restricted + sudo add-apt-repository multiverse sudo apt-get update - name: Install gcc-${{ matrix.compiler.ver }} if: matrix.compiler.name == 'gcc' run: | - sudo apt-get install -y gcc-${{ matrix.compiler.ver }} g++-${{ matrix.compiler.ver }} + sudo apt install -y gcc-${{ matrix.compiler.ver }} g++-${{ matrix.compiler.ver }} echo "CXX=g++-${{ matrix.compiler.ver }}" >> $GITHUB_ENV - name: Install clang-${{ matrix.compiler.ver }} if: matrix.compiler.name == 'clang' run: | - sudo apt-get install -y clang-${{ matrix.compiler.ver }} --install-suggests + sudo apt install -y clang-${{ matrix.compiler.ver }} --install-suggests echo "CXX=clang++-${{ matrix.compiler.ver }}" >> $GITHUB_ENV - name: install openmpi @@ -82,8 +100,13 @@ jobs: run: | sudo apt install -y openmpi-bin libopenmpi-dev + - name: install OpenMP + if: matrix.openmp == 'ON' + run: | + sudo apt-get install -y libomp5-14 libomp-dev + - name: install gsl - run: sudo apt-get install libgsl-dev + run: sudo apt install libgsl-dev # - name: Set compiler environment variables (MPI off) # if: matrix.mpi == 'OFF' @@ -103,4 +126,4 @@ jobs: - name: Compile run: | cp -v -p ${{ matrix.artisoptionsfile }} artisoptions.h - make MPI=${{matrix.mpi}} -j${{ steps.cpu-count.outputs.count}} sn3d exspec + make MPI=${{matrix.mpi}} OPENMP=${{matrix.openmp}} -j${{ steps.cpu-count.outputs.count}} sn3d exspec diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 38eb691a2..71dae98ce 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: # os: ['ubuntu-latest', 'self-hosted'] os: [ubuntu-22.04] testmode: [OFF, ON] - testname: [classicmode, classicmode_3d, kilonova, nebularonezone] + testname: [classicmode_1d_3dgrid, classicmode_3d, kilonova_1d_1dgrid, kilonova_1d_3dgrid, kilonova_2d_2dgrid, kilonova_2d_3dgrid, nebularonezone_1d_3dgrid] exclude: - os: self-hosted testmode: ON @@ -27,7 +27,7 @@ jobs: runs-on: ${{ matrix.os }} timeout-minutes: 45 - name: ${{ matrix.testname }} ${{ matrix.testmode == 'ON' && ' testmode ON' || ''}} + name: ${{ matrix.testname }}${{ matrix.testmode == 'ON' && ' testmode ON' || ''}} steps: - uses: actions/checkout@v3 @@ -38,11 +38,11 @@ jobs: if: matrix.os != 'selfhosted' run: | git status - sudo apt-get update - sudo apt-get install -y gcc-12 g++-12 - sudo apt-get install -y libgsl-dev + sudo apt update + sudo apt install -y gcc-13 g++-13 + sudo apt install -y libgsl-dev sudo apt install -y openmpi-bin libopenmpi-dev - echo "OMPI_CXX=g++-12" >> $GITHUB_ENV + echo "OMPI_CXX=g++-13" >> $GITHUB_ENV - name: CPU type and core count id: cpu-count @@ -52,8 +52,7 @@ jobs: # cache this for classic options because the super low integration tolerance makes generation of the file very slow - name: Cache ratecoeff.dat - if: matrix.testname == 'classicmode' || matrix.testname == 'classicmode_3d' - # if: matrix.testname == 'classicmode' && matrix.testmode != 'ON' + if: matrix.testname == 'classicmode_1d_3dgrid' || matrix.testname == 'classicmode_3d' uses: actions/cache@v3 with: path: tests/${{ matrix.testname }}_testrun/ratecoeff.dat @@ -62,7 +61,7 @@ jobs: tests/${{ matrix.testname }}_testrun/ratecoeff.dat- - name: Cache test atomic data - if: matrix.testname != 'classicmode' + if: ${{ !startsWith(matrix.testname, 'classicmode_1d') }} uses: actions/cache@v3 id: cache-testatomicdata with: @@ -70,7 +69,7 @@ jobs: key: tests/atomicdata_feconi.tar.xz - name: Cache test atomic data classic - if: matrix.testname == 'classicmode' + if: ${{ startsWith(matrix.testname, 'classicmode_1d') }} uses: actions/cache@v3 id: cache-testatomicdata-classic with: @@ -124,8 +123,7 @@ jobs: if: always() && matrix.os != 'selfhosted' && matrix.testmode == 'OFF' working-directory: tests/${{ matrix.testname }}_testrun run: | - md5sum *.out job0/*.out - + md5sum *.out job0/*.out | tee ../${{ matrix.testname }}_inputfiles/results_md5_job0.txt if [ -f results_md5_job0.txt ]; then md5sum -c results_md5_job0.txt; else echo "results_md5_job0.txt not found"; fi - name: Run test job1 resume @@ -152,6 +150,11 @@ jobs: working-directory: tests/${{ matrix.testname }}_testrun/ run: cat job1/output_0-0.txt + - name: cat job1 deposition.out + if: always() + working-directory: tests/${{ matrix.testname }}_testrun/ + run: cat deposition.out + - name: Run exspec if: always() working-directory: tests/${{ matrix.testname }}_testrun/ @@ -174,7 +177,7 @@ jobs: if: always() && matrix.os != 'selfhosted' && matrix.testmode == 'OFF' working-directory: tests/${{ matrix.testname }}_testrun run: | - md5sum *.out job1/*.out + md5sum *.out job1/*.out | tee ../${{ matrix.testname }}_inputfiles/results_md5_final.txt if [ -f results_md5_final.txt ]; then md5sum -c results_md5_final.txt; else echo "results_md5_final.txt not found"; fi - name: Prepare for next steps @@ -192,6 +195,13 @@ jobs: name: test-${{ matrix.testname }}-output path: tests/${{ matrix.testname }}_testrun/output + - name: Upload checksum files + uses: actions/upload-artifact@v3 + if: always() && matrix.os != 'selfhosted' && matrix.testmode == 'OFF' + with: + name: ${{ matrix.testname }}_inputfiles + path: tests/${{ matrix.testname }}_inputfiles/results_md5* + - name: Set up Python if: always() && matrix.os != 'selfhosted' && matrix.testmode == 'OFF' uses: actions/setup-python@v4 @@ -252,3 +262,21 @@ jobs: # cp input-newrun.txt input.txt # touch output_0-0.txt # time mpirun -np 2 ./sn3d + + combine_checksums: + needs: testmodels + if: always() + runs-on: ubuntu-latest + steps: + - name: Download test output + uses: actions/download-artifact@v3 + + - name: List all files + if: always() + run: find . + + - name: Upload bundled checksum files + uses: actions/upload-artifact@v3 + with: + name: checksums + path: '*_inputfiles/results_md5*.txt' diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 190b96429..1bfa2da8f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ fail_fast: false repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: check-added-large-files args: [--maxkb=800] diff --git a/CMakeLists.txt b/CMakeLists.txt index 588c87c55..ee4ff501f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.9) +cmake_minimum_required(VERSION 3.26) project(artis) set(default_build_type "Release") @@ -11,16 +11,18 @@ set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}) include_directories("${PROJECT_SOURCE_DIR}") set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED True) -set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) +#set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) -set(SN3D_SOURCES sn3d.cc atomic.cc boundary.cc emissivities.cc gamma.cc globals.cc grey_emissivities.cc grid.cc input.cc kpkt.cc light_curve.cc ltepop.cc macroatom.cc nltepop.cc nonthermal.cc decay.cc packets.cc photo_electric.cc polarization.cc radfield.cc ratecoeff.cc rpkt.cc stats.cc thermalbalance.cc update_grid.cc update_packets.cc vectors.cc vpkt.cc md5.cc +set(SN3D_SOURCES sn3d.cc atomic.cc boundary.cc gammapkt.cc globals.cc grid.cc input.cc kpkt.cc light_curve.cc ltepop.cc macroatom.cc nltepop.cc nonthermal.cc decay.cc packet.cc radfield.cc ratecoeff.cc rpkt.cc spectrum.cc stats.cc thermalbalance.cc update_grid.cc update_packets.cc vectors.cc vpkt.cc md5.cc) add_executable(sn3d ${SN3D_SOURCES}) -set(EXSPEC_SOURCES exspec.cc grid.cc globals.cc input.cc vectors.cc packets.cc update_grid.cc update_packets.cc gamma.cc boundary.cc macroatom.cc decay.cc rpkt.cc kpkt.cc photo_electric.cc emissivities.cc grey_emissivities.cc ltepop.cc atomic.cc ratecoeff.cc thermalbalance.cc light_curve.cc spectrum.cc polarization.cc nltepop.cc nonthermal.cc radfield.cc stats.cc vpkt.cc md5.cc) +set(EXSPEC_SOURCES exspec.cc grid.cc globals.cc input.cc vectors.cc packet.cc update_grid.cc update_packets.cc gammapkt.cc boundary.cc macroatom.cc decay.cc rpkt.cc kpkt.cc ltepop.cc atomic.cc ratecoeff.cc thermalbalance.cc light_curve.cc spectrum.cc nltepop.cc nonthermal.cc radfield.cc stats.cc vpkt.cc md5.cc) add_executable(exspec ${EXSPEC_SOURCES}) +#if(UNIX AND NOT APPLE) if(UNIX AND NOT APPLE) find_package(MPI) include_directories(SYSTEM ${MPI_INCLUDE_PATH}) @@ -32,7 +34,7 @@ add_compile_options("-Wall" "-Wextra") string(APPEND CMAKE_CXX_FLAGS_DEBUG "-g") string(APPEND CMAKE_CXX_FLAGS_RELEASE "-O3") -set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -march=native") +#set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -march=native") add_compile_definitions(HAVE_INLINE) add_compile_definitions(GSL_RANGE_CHECK_OFF) diff --git a/Makefile b/Makefile index 45a5a3905..0955d5017 100644 --- a/Makefile +++ b/Makefile @@ -3,8 +3,8 @@ # place in architecture folder, e.g. build/arm64 BUILD_DIR = build/$(shell uname -m) -CXXFLAGS += -std=c++20 -fstrict-aliasing -ftree-vectorize -g -flto=auto -Werror -Werror=undef -# CXXFLAGS += -Wpedantic -Wextra -Wall +CXXFLAGS += -std=c++20 -fstrict-aliasing -ftree-vectorize -flto=auto + # CXXFLAGS += -Wunreachable-code ifeq ($(shell uname -s),Darwin) @@ -18,6 +18,7 @@ ifeq ($(shell uname -s),Darwin) CXXFLAGS += -march=native endif + CXXFLAGS += -fno-omit-frame-pointer # CXXFLAGS += -Rpass=loop-vectorize # CXXFLAGS += -Rpass-missed=loop-vectorize # CXXFLAGS += -Rpass-analysis=loop-vectorize @@ -77,20 +78,24 @@ ifeq ($(TESTMODE),ON) CXXFLAGS += -DTESTMODE=true -O3 -DLIBCXX_ENABLE_DEBUG_MODE # makes GitHub actions classic test run forever? # CXXFLAGS += -D_GLIBCXX_DEBUG - CXXFLAGS += -fsanitize=address -fno-omit-frame-pointer -fno-common + CXXFLAGS += -fsanitize=address,undefined -fno-omit-frame-pointer -fno-common BUILD_DIR := $(BUILD_DIR)_testmode else # skip array range checking for better performance and use optimizations CXXFLAGS += -DTESTMODE=false -DGSL_RANGE_CHECK_OFF -O3 endif -CXXFLAGS += -Winline -Wall -Wpedantic -Wredundant-decls -Wundef -Wno-unused-parameter -Wno-unused-function -Wstrict-aliasing -Wno-inline +CXXFLAGS += -Werror -Werror=undef -Winline -Wall -Wpedantic -Wredundant-decls -Wundef -Wno-unused-parameter -Wno-unused-function -Wstrict-aliasing -Wno-inline -ifeq ($(MPI),ON) -else ifeq ($(MPI),OFF) -else ifeq ($(MPI),) +ifeq ($(MPI),) # MPI option not specified. set to true by default MPI := ON +endif +ifeq ($(MPI),ON) + CXX = mpicxx + CXXFLAGS += -DMPI_ON=true + BUILD_DIR := $(BUILD_DIR)_mpi +else ifeq ($(MPI),OFF) else $(error bad value for MPI option. Should be ON or OFF) endif @@ -102,17 +107,14 @@ else $(error bad value for testmode option. Should be ON or OFF) endif -ifeq ($(MPI),ON) - CXX = mpicxx - CXXFLAGS += -DMPI_ON=true - BUILD_DIR := $(BUILD_DIR)_mpi -endif - ifeq ($(OPENMP),ON) - CXXFLAGS += -Xpreprocessor - CXXFLAGS += -fopenmp + CXXFLAGS += -Xpreprocessor -fopenmp LDFLAGS += -lomp BUILD_DIR := $(BUILD_DIR)_openmp +else ifeq ($(OPENMP),OFF) +else ifeq ($(OPENMP),) +else +$(error bad value for testmode option. Should be ON or OFF) endif ### use pg when you want to use gprof profiler @@ -137,7 +139,7 @@ sn3d: $(sn3d_objects) -include $(sn3d_dep) sn3dwhole: version.h - $(CXX) $(CXXFLAGS) $(sn3d_files) $(LDFLAGS) -o sn3d + $(CXX) $(CXXFLAGS) -g $(sn3d_files) $(LDFLAGS) -o sn3d $(BUILD_DIR)/%.o: %.cc artisoptions.h Makefile @mkdir -p $(@D) diff --git a/README.old b/README.old index fb9f44cda..bcfeb17ae 100644 --- a/README.old +++ b/README.old @@ -208,7 +208,7 @@ code until 2012-07-30: 2009-07-15, v108 - Modified initial grey approximation now calculates an optical depth to the surface of the simulation - volume using kappa_grey. + volume using chi_grey. - As of now (2009-07-15) the local thomson and grey optical depth in a cell and the depth to the surface are save in the estimator files. This requires @@ -226,7 +226,7 @@ code until 2012-07-30: files. - Proper initialisation of absorption counters added (2009-05-30). - Changes to the initial grey approximation, reintroducing - the concept of kappa_grey. + the concept of chi_grey. - Array boundaries which have to be changed for each run moved to types.h diff --git a/artisoptions_christinenonthermal.h b/artisoptions_christinenonthermal.h index 3f1fed21a..9c5cf6ead 100644 --- a/artisoptions_christinenonthermal.h +++ b/artisoptions_christinenonthermal.h @@ -8,14 +8,11 @@ constexpr int MPKTS = 10000; -constexpr int GRID_TYPE = GRID_UNIFORM; +constexpr int GRID_TYPE = GRID_CARTESIAN3D; constexpr int CUBOID_NCOORDGRID_X = 100; constexpr int CUBOID_NCOORDGRID_Y = 100; constexpr int CUBOID_NCOORDGRID_Z = 100; - -constexpr bool NLTE_POPS_ON = true; - -constexpr bool NLTE_POPS_ALL_IONS_SIMULTANEOUS = true; +constexpr bool FORCE_SPHERICAL_ESCAPE_SURFACE = false; constexpr int NLTEITER = 30; @@ -28,6 +25,8 @@ constexpr bool LEVEL_IS_NLTE(int element_z, int ionstage, int level) { constexpr bool LTEPOP_EXCITATION_USE_TJ = false; +constexpr bool FORCE_SAHA_ION_BALANCE(int element_z) { return false; } + constexpr bool single_level_top_ion = false; constexpr bool single_ground_level = false; @@ -139,8 +138,6 @@ constexpr double FIXED_TIMESTEP_WIDTH = -1.; constexpr double TIMESTEP_TRANSITION_TIME = -1.; -constexpr bool USE_GSL_RANDOM = true; - constexpr bool KEEP_ALL_RESTART_FILES = false; constexpr bool BFCOOLING_USELEVELPOPNOTIONPOP = false; diff --git a/artisoptions_classic.h b/artisoptions_classic.h index d27685f85..08eb7f280 100644 --- a/artisoptions_classic.h +++ b/artisoptions_classic.h @@ -8,14 +8,11 @@ constexpr int MPKTS = 100000; -constexpr int GRID_TYPE = GRID_UNIFORM; +constexpr int GRID_TYPE = GRID_CARTESIAN3D; constexpr int CUBOID_NCOORDGRID_X = 100; constexpr int CUBOID_NCOORDGRID_Y = 100; constexpr int CUBOID_NCOORDGRID_Z = 100; - -constexpr bool NLTE_POPS_ON = false; - -constexpr bool NLTE_POPS_ALL_IONS_SIMULTANEOUS = false; +constexpr bool FORCE_SPHERICAL_ESCAPE_SURFACE = false; constexpr int NLTEITER = 30; @@ -23,6 +20,8 @@ constexpr bool LEVEL_IS_NLTE(int element_z, int ionstage, int level) { return fa constexpr bool LTEPOP_EXCITATION_USE_TJ = true; +constexpr bool FORCE_SAHA_ION_BALANCE(int element_z) { return false; } + constexpr bool single_level_top_ion = true; constexpr bool single_ground_level = true; @@ -135,8 +134,6 @@ constexpr double FIXED_TIMESTEP_WIDTH = -1.; constexpr double TIMESTEP_TRANSITION_TIME = -1.; -constexpr bool USE_GSL_RANDOM = true; - constexpr bool KEEP_ALL_RESTART_FILES = false; constexpr bool BFCOOLING_USELEVELPOPNOTIONPOP = false; diff --git a/artisoptions_doc.md b/artisoptions_doc.md index ba5da3d66..a3f56f342 100644 --- a/artisoptions_doc.md +++ b/artisoptions_doc.md @@ -2,26 +2,26 @@ // Number of energy packets per process (MPI rank). OpenMP threads share these packets constexpr int MPKTS; -constexpr int GRID_TYPE = {GRID_UNIFORM, GRID_SPHERICAL1D} +constexpr int GRID_TYPE = {GRID_CARTESIAN3D, GRID_CYLINDRICAL2D, GRID_SPHERICAL1D} + +// for GRID_CARTESIAN3D, set the dimensions. This will have no effect with a 3D model.txt since they will be set to match the input constexpr int CUBOID_NCOORDGRID_X; constexpr int CUBOID_NCOORDGRID_Y; constexpr int CUBOID_NCOORDGRID_Z; -// non-LTE population solver -constexpr bool NLTE_POPS_ON; - -// solve the NLTE population matrix equation simultaneously for levels of all ions of an element -constexpr bool NLTE_POPS_ALL_IONS_SIMULTANEOUS; +// for 2D cylindrical and 3D Cartesian, remove the corners (v > vmax) to force a spherical escape surface +constexpr bool FORCE_SPHERICAL_ESCAPE_SURFACE; // maximum number of NLTE/Te/Spencer-Fano iterations constexpr int NLTEITER; -// this macro function determines which levels of which ions will be treated in full NLTE (if NLTE_POPS_ON is true) +// this macro function determines which levels of which ions will be treated in full NLTE // for now, all NLTE levels should be contiguous and include the ground state // (i.e. level indices < X should return true for some X) constexpr bool LEVEL_IS_NLTE(int element_z, int ionstage, int level) { return false; } // Use TJ radiation density temperature for Boltzmann excitation formua instead of electron temperature Te +// This is default on for classic, and off for nebularnlte, where it affects the super-level constexpr bool LTEPOP_EXCITATION_USE_TJ = false; // Only include a single level for the highest ion stage @@ -63,6 +63,8 @@ constexpr double RECOMBCALIBRATION_T_ELEC; // Polarisation for real packets constexpr bool DIPOLE; + +// Only affects exspec and enables writing specpol.out, emissionpol.out, absorptionpol.out constexpr bool POL_ON; // Polarisation for virtual packets @@ -212,8 +214,6 @@ constexpr double FIXED_TIMESTEP_WIDTH; constexpr double TIMESTEP_TRANSITION_TIME; -constexpr bool USE_GSL_RANDOM; - // once a new gridsave and packets*.tmp have been written, don't delete the previous set constexpr bool KEEP_ALL_RESTART_FILES; diff --git a/artisoptions_kilonova_lte.h b/artisoptions_kilonova_lte.h index df1a277d4..02b8000fc 100644 --- a/artisoptions_kilonova_lte.h +++ b/artisoptions_kilonova_lte.h @@ -8,20 +8,19 @@ constexpr int MPKTS = 15000; -constexpr int GRID_TYPE = GRID_UNIFORM; +constexpr int GRID_TYPE = GRID_CARTESIAN3D; constexpr int CUBOID_NCOORDGRID_X = 50; constexpr int CUBOID_NCOORDGRID_Y = 50; constexpr int CUBOID_NCOORDGRID_Z = 50; - -constexpr bool NLTE_POPS_ON = false; - -constexpr bool NLTE_POPS_ALL_IONS_SIMULTANEOUS = true; +constexpr bool FORCE_SPHERICAL_ESCAPE_SURFACE = false; constexpr int NLTEITER = 30; constexpr bool LEVEL_IS_NLTE(int element_z, int ionstage, int level) { return false; } -constexpr bool LTEPOP_EXCITATION_USE_TJ = false; +constexpr bool LTEPOP_EXCITATION_USE_TJ = true; + +constexpr bool FORCE_SAHA_ION_BALANCE(int element_z) { return false; } constexpr bool single_level_top_ion = false; @@ -134,8 +133,6 @@ constexpr double FIXED_TIMESTEP_WIDTH = -1.; constexpr double TIMESTEP_TRANSITION_TIME = -1.; -constexpr bool USE_GSL_RANDOM = true; - constexpr bool KEEP_ALL_RESTART_FILES = false; constexpr bool BFCOOLING_USELEVELPOPNOTIONPOP = false; diff --git a/artisoptions_nltenebular.h b/artisoptions_nltenebular.h index 55689fcab..4de2507d9 100644 --- a/artisoptions_nltenebular.h +++ b/artisoptions_nltenebular.h @@ -8,14 +8,11 @@ constexpr int MPKTS = 1000000; -constexpr int GRID_TYPE = GRID_UNIFORM; +constexpr int GRID_TYPE = GRID_CARTESIAN3D; constexpr int CUBOID_NCOORDGRID_X = 50; constexpr int CUBOID_NCOORDGRID_Y = 50; constexpr int CUBOID_NCOORDGRID_Z = 50; - -constexpr bool NLTE_POPS_ON = true; - -constexpr bool NLTE_POPS_ALL_IONS_SIMULTANEOUS = true; +constexpr bool FORCE_SPHERICAL_ESCAPE_SURFACE = false; constexpr int NLTEITER = 30; @@ -28,6 +25,8 @@ constexpr bool LEVEL_IS_NLTE(int element_z, int ionstage, int level) { constexpr bool LTEPOP_EXCITATION_USE_TJ = false; +constexpr bool FORCE_SAHA_ION_BALANCE(int element_z) { return false; } + constexpr bool single_level_top_ion = false; constexpr bool single_ground_level = false; @@ -142,8 +141,6 @@ constexpr double FIXED_TIMESTEP_WIDTH = -1.; constexpr double TIMESTEP_TRANSITION_TIME = -1.; -constexpr bool USE_GSL_RANDOM = true; - constexpr bool KEEP_ALL_RESTART_FILES = false; constexpr bool BFCOOLING_USELEVELPOPNOTIONPOP = false; diff --git a/artisoptions_nltewithoutnonthermal.h b/artisoptions_nltewithoutnonthermal.h index e83015c95..d42344dcb 100644 --- a/artisoptions_nltewithoutnonthermal.h +++ b/artisoptions_nltewithoutnonthermal.h @@ -8,14 +8,11 @@ constexpr int MPKTS = 10000; -constexpr int GRID_TYPE = GRID_UNIFORM; +constexpr int GRID_TYPE = GRID_CARTESIAN3D; constexpr int CUBOID_NCOORDGRID_X = 100; constexpr int CUBOID_NCOORDGRID_Y = 100; constexpr int CUBOID_NCOORDGRID_Z = 100; - -constexpr bool NLTE_POPS_ON = true; - -constexpr bool NLTE_POPS_ALL_IONS_SIMULTANEOUS = true; +constexpr bool FORCE_SPHERICAL_ESCAPE_SURFACE = false; constexpr int NLTEITER = 30; @@ -28,6 +25,8 @@ constexpr bool LEVEL_IS_NLTE(int element_z, int ionstage, int level) { constexpr bool LTEPOP_EXCITATION_USE_TJ = false; +constexpr bool FORCE_SAHA_ION_BALANCE(int element_z) { return false; } + constexpr bool single_level_top_ion = true; constexpr bool single_ground_level = true; @@ -138,8 +137,6 @@ constexpr double FIXED_TIMESTEP_WIDTH = 0.1; constexpr double TIMESTEP_TRANSITION_TIME = 5; -constexpr bool USE_GSL_RANDOM = true; - constexpr bool KEEP_ALL_RESTART_FILES = false; constexpr bool BFCOOLING_USELEVELPOPNOTIONPOP = true; diff --git a/atomic.cc b/atomic.cc index 7e995d3d6..693ad4746 100644 --- a/atomic.cc +++ b/atomic.cc @@ -1,6 +1,7 @@ #include "atomic.h" #include +#include #include "artisoptions.h" #include "grid.h" @@ -9,7 +10,6 @@ double last_phixs_nuovernuedge = -1; // last photoion cross section point as a factor of nu_edge = last_phixs_nuovernuedge -int nelements = 0; // total number of elements included in the simulation int maxnions = 0; // highest number of ions for any element int includedions = 0; // number of ions of any element std::array phixs_file_version_exists; @@ -57,8 +57,8 @@ auto get_tau_sobolev(const int modelgridindex, const int lineindex, const double return tau_sobolev; } -auto get_nntot(int modelgridindex) -> double -// total ion (nuclei) density +auto get_nnion_tot(int modelgridindex) -> double +// total density of nuclei { double nntot = 0.; for (int element = 0; element < get_nelements(); element++) { @@ -73,9 +73,6 @@ auto is_nlte(const int element, const int ion, const int level) -> bool // (note this function returns true for the ground state, // although it is stored separately from the excited NLTE states) { - if (!NLTE_POPS_ON) { - return false; - } return LEVEL_IS_NLTE(get_atomicnumber(element), get_ionstage(element, ion), level); // defined in artisoptions.h } @@ -83,7 +80,7 @@ auto is_nlte(const int element, const int ion, const int level) -> bool auto level_isinsuperlevel(const int element, const int ion, const int level) -> bool // ion has NLTE levels, but this one is not NLTE => is in the superlevel { - return (NLTE_POPS_ON && !is_nlte(element, ion, level) && level != 0 && (get_nlevels_nlte(element, ion) > 0)); + return (!is_nlte(element, ion, level) && level != 0 && (get_nlevels_nlte(element, ion) > 0)); } auto photoionization_crosssection_fromtable(const float *const photoion_xs, const double nu_edge, const double nu) @@ -98,7 +95,7 @@ auto photoionization_crosssection_fromtable(const float *const photoion_xs, cons // return 1.; // return 1. * pow(nu_edge / nu, 3); - float sigma_bf = NAN; + float sigma_bf = 0.; if (phixs_file_version_exists[1] && !phixs_file_version_exists[2]) { // classic mode: no interpolation @@ -156,9 +153,9 @@ auto photoionization_crosssection_fromtable(const float *const photoion_xs, cons return sigma_bf; } -void set_nelements(const int nelements_in) { nelements = nelements_in; } +void set_nelements(const int nelements_in) { globals::elements.resize(nelements_in); } -auto get_nelements() -> int { return nelements; } +auto get_nelements() -> int { return globals::elements.size(); } auto get_atomicnumber(const int element) -> int /// Returns the atomic number associated with a given elementindex. @@ -173,20 +170,26 @@ auto get_elementindex(const int Z) -> int /// If there is no element with the given atomic number in the atomic data /// a negative value is returned to flag this event. { - for (int i = 0; i < get_nelements(); i++) { - // printf("i %d, Z %d, elements[i].anumber %d\n",i,Z,elements[i].anumber); - if (Z == globals::elements[i].anumber) { - return i; - } + const auto elem = + std::ranges::find_if(globals::elements, [Z](const elementlist_entry &element) { return element.anumber == Z; }); + if (elem != globals::elements.end()) { + return std::distance(globals::elements.begin(), elem); } - // printout("[debug] get_elementindex: element Z=%d was not found in atomic data ... skip readin of cross sections for - // this element\n",Z); printout("[fatal] get_elementindex: element Z=%d was not found in atomic data ... abort\n"); - // abort();; + // printout("[debug] get_elementindex: element Z=%d was not found in atomic data ... skip readin of cross sections + // for this element\n",Z); printout("[fatal] get_elementindex: element Z=%d was not found in atomic data ... + // abort\n"); abort();; return -100; } -void increase_includedions(const int nions) { includedions += nions; } +void update_includedions_maxnions() { + includedions = 0; + maxnions = 0; + for (int element = 0; element < get_nelements(); element++) { + includedions += get_nions(element); + maxnions = std::max(maxnions, get_nions(element)); + } +} auto get_includedions() -> int // returns the number of ions of all elements combined @@ -197,11 +200,7 @@ auto get_includedions() -> int void update_max_nions(const int nions) // Will ensure that maxnions is always greater than or equal to the number of nions // this is called at startup once per element with the number of ions -{ - if (nions > maxnions || maxnions < 0) { - maxnions = nions; - } -} +{} auto get_max_nions() -> int { // number greater than or equal to nions(element) for all elements @@ -234,6 +233,19 @@ auto get_nlevels(const int element, const int ion) -> int return globals::elements[element].ions[ion].nlevels; } +auto elem_has_nlte_levels(const int element) -> bool { return globals::elements[element].has_nlte_levels; } + +auto elem_has_nlte_levels_search(const int element) -> bool { + for (int ion = 0; ion < get_nions(element); ion++) { + for (int level = 1; level < get_nlevels(element, ion); level++) { + if (is_nlte(element, ion, level)) { + return true; + } + } + } + return false; +} + auto get_nlevels_nlte(const int element, const int ion) -> int // Returns the number of NLTE levels associated with with a specific ion given // its elementindex and ionindex. Includes the superlevel if there is one but does not include the ground state diff --git a/atomic.h b/atomic.h index c687e7cab..170f4e620 100644 --- a/atomic.h +++ b/atomic.h @@ -13,7 +13,7 @@ int get_continuumindex_phixstargetindex(int element, int ion, int level, int phi int get_continuumindex(int element, int ion, int level, int upperionlevel); int get_phixtargetindex(int element, int ion, int level, int upperionlevel); double get_tau_sobolev(int modelgridindex, int lineindex, double t_current); -double get_nntot(int modelgridindex); +auto get_nnion_tot(int modelgridindex) -> double; bool is_nlte(int element, int ion, int level); bool level_isinsuperlevel(int element, int ion, int level); double photoionization_crosssection_fromtable(const float *photoion_xs, double nu_edge, double nu); @@ -21,9 +21,8 @@ void set_nelements(int nelements_in); int get_nelements(); int get_atomicnumber(int element); int get_elementindex(int Z); -void increase_includedions(int nions); int get_includedions(); -void update_max_nions(int nions); +void update_includedions_maxnions(); int get_max_nions(); int get_nions(int element); int get_ionstage(int element, int ion); @@ -49,5 +48,7 @@ void set_nuptrans(int element, int ion, int level, int nuptrans); double einstein_spontaneous_emission(int lineindex); double photoionization_crosssection(int element, int ion, int level, double nu_edge, double nu); double get_phixs_threshold(int element, int ion, int level, int phixstargetindex); +bool elem_has_nlte_levels(int element); +bool elem_has_nlte_levels_search(int element); #endif // ATOMIC_H diff --git a/boundary.cc b/boundary.cc deleted file mode 100644 index 38e195d7c..000000000 --- a/boundary.cc +++ /dev/null @@ -1,372 +0,0 @@ -// #include -#include "boundary.h" - -#include - -#include "grid.h" -#include "rpkt.h" -#include "sn3d.h" -#include "stats.h" -#include "update_packets.h" -#include "vectors.h" - -static auto get_shellcrossdist(const double pos[3], const double dir[3], const double shellradius, - const bool isinnerboundary, const double tstart) -> double -// find the closest forward distance to the intersection of a ray with an expanding spherical shell -// return -1 if there are no forward intersections (or if the intersection is tangential to the shell) -{ - assert_always(shellradius > 0); - constexpr bool debug = false; - if constexpr (debug) { - printout("get_shellcrossdist isinnerboundary %d\n", isinnerboundary); - printout("shellradius %g tstart %g len(pos) %g\n", shellradius, tstart, vec_len(pos)); - } - const double speed = vec_len(dir) * CLIGHT_PROP; - const double a = dot(dir, dir) - pow(shellradius / tstart / speed, 2); - const double b = 2 * (dot(dir, pos) - pow(shellradius, 2) / tstart / speed); - const double c = dot(pos, pos) - pow(shellradius, 2); - - const double discriminant = pow(b, 2) - 4 * a * c; - - if (discriminant < 0) { - // no intersection - assert_always(shellradius < vec_len(pos)); - if constexpr (debug) { - printout("no intersection\n"); - } - return -1; - } - if (discriminant > 0) { - // two intersections - double d1 = (-b + sqrt(discriminant)) / 2 / a; - double d2 = (-b - sqrt(discriminant)) / 2 / a; - - double posfinal1[3]; - double posfinal2[3]; - - cblas_dcopy(3, pos, 1, posfinal1, 1); // posfinal1 = pos - cblas_daxpy(3, d1, dir, 1, posfinal1, 1); // posfinal1 += d1 * dir; - - cblas_dcopy(3, pos, 1, posfinal2, 1); - cblas_daxpy(3, d2, dir, 1, posfinal2, 1); - - // for (int d = 0; d < 3; d++) { - // posfinal1[d] = pos[d] + d1 * dir[d]; - // posfinal2[d] = pos[d] + d2 * dir[d]; - // } - - const double shellradiusfinal1 = shellradius / tstart * (tstart + d1 / speed); - const double shellradiusfinal2 = shellradius / tstart * (tstart + d2 / speed); - // printout("solution1 d1 %g radiusfinal1 %g shellradiusfinal1 %g\n", d1, vec_len(posfinal1), shellradiusfinal1); - // printout("solution2 d2 %g radiusfinal2 %g shellradiusfinal2 %g\n", d2, vec_len(posfinal2), shellradiusfinal2); - assert_always(fabs(vec_len(posfinal1) / shellradiusfinal1 - 1.) < 1e-3); - assert_always(fabs(vec_len(posfinal2) / shellradiusfinal2 - 1.) < 1e-3); - - // invalidate any solutions that require entering the boundary from the wrong radial direction - if (isinnerboundary) { - if (dot(posfinal1, dir) > 0.) { - d1 = -1; - } - if (dot(posfinal2, dir) > 0.) { - d2 = -1; - } - } else { - if (dot(posfinal1, dir) < 0.) { - d1 = -1; - } - if (dot(posfinal2, dir) < 0.) { - d2 = -1; - } - } - - // negative d means in the reverse direction along the ray - // ignore negative d values, and if two are positive then return the smaller one - if (d1 < 0 && d2 < 0) { - return -1; - } - if (d2 < 0) { - return d1; - } - if (d1 < 0) { - return d2; - } - return fmin(d1, d2); - - } // exactly one intersection - // ignore this and don't change which cell the packet is in - assert_always(shellradius <= vec_len(pos)); - printout("single intersection\n"); - return -1.; -} - -auto boundary_cross(struct packet *const pkt_ptr, int *snext) -> double -/// Basic routine to compute distance to a cell boundary. -{ - const double tstart = pkt_ptr->prop_time; - - // There are six possible boundary crossings. Each of the three - // cartesian coordinates may be taken in turn. For x, the packet - // trajectory is - // x = x0 + (dir.x) * c * (t - tstart) - // the boundries follow - // x+/- = x+/-(tmin) * (t/tmin) - // so the crossing occurs when - // t = (x0 - (dir.x)*c*tstart)/(x+/-(tmin)/tmin - (dir.x)c) - - // Modified so that it also returns the distance to the closest cell - // boundary, regardless of direction. - - // d is used to loop over the coordinate indicies 0,1,2 for x,y,z - - const int cellindex = pkt_ptr->where; - - // the following four vectors are in grid coordinates, so either x,y,z or r - const int ndim = grid::get_ngriddimensions(); - assert_testmodeonly(ndim <= 3); - double initpos[3] = {0}; // pkt_ptr->pos converted to grid coordinates - double cellcoordmax[3] = {0}; - double vel[3] = {0}; // pkt_ptr->dir * CLIGHT_PROP converted to grid coordinates - - if (GRID_TYPE == GRID_UNIFORM) { - // XYZ coordinates - for (int d = 0; d < ndim; d++) { - initpos[d] = pkt_ptr->pos[d]; - cellcoordmax[d] = grid::get_cellcoordmax(cellindex, d); - vel[d] = pkt_ptr->dir[d] * CLIGHT_PROP; - } - } else if (GRID_TYPE == GRID_SPHERICAL1D) { - // the only coordinate is radius from the origin - initpos[0] = vec_len(pkt_ptr->pos); - cellcoordmax[0] = grid::get_cellcoordmax(cellindex, 0); - vel[0] = dot(pkt_ptr->pos, pkt_ptr->dir) / vec_len(pkt_ptr->pos) * CLIGHT_PROP; // radial velocity - } else { - assert_always(false); - } - - // for (int d = 0; d < ndim; d++) - // { - // if (initpos[d] < grid::get_cellcoordmin(cellindex, d) || initpos[d] > cellcoordmax[d]) - // { - // printout("WARNING: packet should have already escaped.\n"); - // *snext = -99; - // return 0; - // } - // } - - // printout("boundary.c: x0 %g, y0 %g, z0 %g\n", initpos[0] initpos[1] initpos[2]); - // printout("boundary.c: vx %g, vy %g, vz %g\n",vel[0],vel[1],vel[2]); - // printout("boundary.c: cellxmin %g, cellymin %g, cellzmin %g\n",grid::get_cellcoordmin(cellindex, - // 0),grid::get_cellcoordmin(cellindex, 1),grid::get_cellcoordmin(cellindex, 2)); printout("boundary.c: cellxmax %g, - // cellymax %g, cellzmax %g\n",cellcoordmax[0],cellcoordmax[1],cellcoordmax[2]); - - enum cell_boundary last_cross = pkt_ptr->last_cross; - enum cell_boundary const negdirections[3] = {NEG_X, NEG_Y, NEG_Z}; // 'X' might actually be radial coordinate - enum cell_boundary const posdirections[3] = {POS_X, POS_Y, POS_Z}; - - // printout("checking inside cell boundary\n"); - for (int d = 0; d < ndim; d++) { - // flip is either zero or one to indicate +ve and -ve boundaries along the selected axis - for (int flip = 0; flip < 2; flip++) { - enum cell_boundary const direction = flip != 0 ? posdirections[d] : negdirections[d]; - enum cell_boundary const invdirection = flip == 0 ? posdirections[d] : negdirections[d]; - const int cellindexstride = - flip != 0 ? -grid::get_coordcellindexincrement(d) : grid::get_coordcellindexincrement(d); - - bool isoutside_thisside = false; - if (flip != 0) { - isoutside_thisside = initpos[d] < (grid::get_cellcoordmin(cellindex, d) / globals::tmin * tstart - - 10.); // 10 cm accuracy tolerance - } else { - isoutside_thisside = initpos[d] > (cellcoordmax[d] / globals::tmin * tstart + 10.); - } - - if (isoutside_thisside && (last_cross != direction)) { - // for (int d2 = 0; d2 < ndim; d2++) - const int d2 = d; - { - printout( - "[warning] packet %d outside coord %d %c%c boundary of cell %d. pkttype %d initpos(tmin) %g, vel %g, " - "cellcoordmin %g, cellcoordmax %g\n", - pkt_ptr->number, d, flip != 0 ? '-' : '+', grid::coordlabel[d], cellindex, pkt_ptr->type, initpos[d2], - vel[d2], grid::get_cellcoordmin(cellindex, d2) / globals::tmin * tstart, - cellcoordmax[d2] / globals::tmin * tstart); - } - printout("globals::tmin %g tstart %g tstart/globals::tmin %g tdecay %g\n", globals::tmin, tstart, - tstart / globals::tmin, pkt_ptr->tdecay); - // printout("[warning] pkt_ptr->number %d\n", pkt_ptr->number); - if (flip != 0) { - printout("[warning] delta %g\n", - (initpos[d] * globals::tmin / tstart) - grid::get_cellcoordmin(cellindex, d)); - } else { - printout("[warning] delta %g\n", cellcoordmax[d] - (initpos[d] * globals::tmin / tstart)); - } - - printout("[warning] dir [%g, %g, %g]\n", pkt_ptr->dir[0], pkt_ptr->dir[1], pkt_ptr->dir[2]); - if ((vel[d] - (initpos[d] / tstart)) > 0) { - if ((grid::get_cellcoordpointnum(cellindex, d) == (grid::ncoordgrid[d] - 1) && cellindexstride > 0) || - (grid::get_cellcoordpointnum(cellindex, d) == 0 && cellindexstride < 0)) { - printout("escaping packet\n"); - *snext = -99; - return 0; - } - *snext = pkt_ptr->where + cellindexstride; - pkt_ptr->last_cross = invdirection; - printout("[warning] swapping packet cellindex from %d to %d and setting last_cross to %d\n", pkt_ptr->where, - *snext, pkt_ptr->last_cross); - return 0; - } - printout("pretending last_cross is %d\n", direction); - last_cross = direction; - } - } - } - - // printout("pkt_ptr->number %d\n", pkt_ptr->number); - // printout("delta1x %g delta2x %g\n", (initpos[0] * globals::tmin/tstart)-grid::get_cellcoordmin(cellindex, 0), - // cellcoordmax[0] - (initpos[0] * globals::tmin/tstart)); printout("delta1y %g delta2y %g\n", (initpos[1] * - // globals::tmin/tstart)-grid::get_cellcoordmin(cellindex, 1), cellcoordmax[1] - (initpos[1] * globals::tmin/tstart)); - // printout("delta1z %g delta2z %g\n", (initpos[2] * globals::tmin/tstart)-grid::get_cellcoordmin(cellindex, 2), - // cellcoordmax[2] - (initpos[2] * globals::tmin/tstart)); printout("dir [%g, %g, %g]\n", - // pkt_ptr->dir[0],pkt_ptr->dir[1],pkt_ptr->dir[2]); - - double t_coordmaxboundary[3]; // time to reach the cell's upper boundary on each coordinate - double t_coordminboundary[3]; // likewise, the lower boundaries (smallest x,y,z or radius value in the cell) - if (GRID_TYPE == GRID_SPHERICAL1D) { - last_cross = NONE; // we will handle this separately by setting d_inner and d_outer negative for invalid directions - const double r_inner = grid::get_cellcoordmin(cellindex, 0) * tstart / globals::tmin; - - const double d_inner = (r_inner > 0.) ? get_shellcrossdist(pkt_ptr->pos, pkt_ptr->dir, r_inner, true, tstart) : -1.; - t_coordminboundary[0] = d_inner / CLIGHT_PROP; - - const double r_outer = cellcoordmax[0] * tstart / globals::tmin; - const double d_outer = get_shellcrossdist(pkt_ptr->pos, pkt_ptr->dir, r_outer, false, tstart); - t_coordmaxboundary[0] = d_outer / CLIGHT_PROP; - - // printout("cell %d\n", pkt_ptr->where); - // printout("initradius %g: velrad %g\n", initpos[0], vel[0]); - // printout("d_outer %g d_inner %g \n", d_outer, d_inner); - // printout("t_plus %g t_minus %g \n", t_coordmaxboundary[0], t_coordminboundary[0]); - // printout("cellrmin %g cellrmax %g\n", - // grid::get_cellcoordmin(cellindex, 0) * tstart / globals::tmin, cellcoordmax[0] * tstart / - // globals::tmin); - // printout("tstart %g\n", tstart); - } else { - // const double overshoot = grid::wid_init(cellindex) * 2e-7; - constexpr double overshoot = 0.; - for (int d = 0; d < 3; d++) { - t_coordmaxboundary[d] = ((initpos[d] - (vel[d] * tstart)) / - ((cellcoordmax[d] + overshoot) - (vel[d] * globals::tmin)) * globals::tmin) - - tstart; - - t_coordminboundary[d] = - ((initpos[d] - (vel[d] * tstart)) / - ((grid::get_cellcoordmin(cellindex, d) - overshoot) - (vel[d] * globals::tmin)) * globals::tmin) - - tstart; - } - } - - // printout("comparing distances. last_cross = %d\n", last_cross); - // We now need to identify the shortest +ve time - that's the one we want. - int choice = 0; /// just a control variable to - double time = 1.e99; - // close = 1.e99; - // printout("bondary.c check value of last_cross = %d\n",last_cross); - for (int d = 0; d < ndim; d++) { - if ((t_coordmaxboundary[d] > 0) && (t_coordmaxboundary[d] < time) && (last_cross != negdirections[d])) { - choice = posdirections[d]; - time = t_coordmaxboundary[d]; - // equivalently if (nxyz[d] == (grid::ncoordgrid[d] - 1)) - // if (grid::get_cellcoordmin(cellindex, d) + 1.5 * grid::wid_init > coordmax[d]) - if (grid::get_cellcoordpointnum(cellindex, d) == (grid::ncoordgrid[d] - 1)) { - *snext = -99; - } else { - *snext = pkt_ptr->where + grid::get_coordcellindexincrement(d); - pkt_ptr->last_cross = posdirections[d]; - } - } - - if ((t_coordminboundary[d] > 0) && (t_coordminboundary[d] < time) && (last_cross != posdirections[d])) { - choice = negdirections[d]; - time = t_coordminboundary[d]; - // equivalently if (nxyz[d] == 0) - // if (grid::get_cellcoordmin(cellindex, d) < - coordmax[d] + 0.5 * grid::wid_init) - if (grid::get_cellcoordpointnum(cellindex, d) == 0) { - *snext = -99; - } else { - *snext = pkt_ptr->where - grid::get_coordcellindexincrement(d); - pkt_ptr->last_cross = negdirections[d]; - } - } - } - - if (choice == 0) { - printout("Something wrong in boundary crossing - didn't find anything.\n"); - printout("packet %d cell %d or %d\n", pkt_ptr->number, cellindex, pkt_ptr->where); - printout("choice %d\n", choice); - printout("globals::tmin %g tstart %g\n", globals::tmin, tstart); - printout("last_cross %d, type %d\n", last_cross, pkt_ptr->type); - for (int d2 = 0; d2 < 3; d2++) { - printout("coord %d: initpos %g dir %g\n", d2, pkt_ptr->pos[d2], pkt_ptr->dir[d2]); - } - printout("|initpos| %g |dir| %g |pos.dir| %g\n", vec_len(pkt_ptr->pos), vec_len(pkt_ptr->dir), - dot(pkt_ptr->pos, pkt_ptr->dir)); - for (int d2 = 0; d2 < ndim; d2++) { - printout("coord %d: txyz_plus %g txyz_minus %g \n", d2, t_coordmaxboundary[d2], t_coordminboundary[d2]); - printout("coord %d: cellcoordmin %g cellcoordmax %g\n", d2, - grid::get_cellcoordmin(cellindex, d2) * tstart / globals::tmin, - cellcoordmax[d2] * tstart / globals::tmin); - } - printout("tstart %g\n", tstart); - - // abort(); - } - - // Now we know what happens. The distance to crossing is.... - double const distance = CLIGHT_PROP * time; - // printout("boundary_cross: time %g distance %g\n", time, distance); - // closest = close; - - return distance; -} - -void change_cell(struct packet *pkt_ptr, int snext) -/// Routine to take a packet across a boundary. -{ - // const int cellindex = pkt_ptr->where; - // printout("[debug] cellnumber %d nne %g\n", cellindex, grid::get_nne(grid::get_cell_modelgridindex(cellindex))); - // printout("[debug] snext %d\n", snext); - - if (snext == -99) { - // Then the packet is exiting the grid. We need to record - // where and at what time it leaves the grid. - pkt_ptr->escape_type = pkt_ptr->type; - pkt_ptr->escape_time = pkt_ptr->prop_time; - pkt_ptr->type = TYPE_ESCAPE; - safeincrement(globals::nesc); - } else { - // Just need to update "where". - pkt_ptr->where = snext; - - stats::increment(stats::COUNTER_CELLCROSSINGS); - } -} - -static auto get_cell(const double pos[3], double t) -> int -/// identify the cell index from a position and a time. -{ - assert_always(GRID_TYPE == GRID_UNIFORM); // other grid types not implemented yet - - const double trat = t / globals::tmin; - const int nx = static_cast((pos[0] - (grid::get_cellcoordmin(0, 0) * trat)) / (grid::wid_init(0) * trat)); - const int ny = static_cast((pos[1] - (grid::get_cellcoordmin(0, 1) * trat)) / (grid::wid_init(0) * trat)); - const int nz = static_cast((pos[2] - (grid::get_cellcoordmin(0, 2) * trat)) / (grid::wid_init(0) * trat)); - - const int cellindex = nx + (grid::ncoordgrid[0] * ny) + (grid::ncoordgrid[0] * grid::ncoordgrid[1] * nz); - - // do a check - for (int n = 0; n < grid::get_ngriddimensions(); n++) { - assert_always(pos[n] >= grid::get_cellcoordmin(cellindex, n)); - assert_always(pos[n] <= grid::get_cellcoordmax(cellindex, n)); - } - return cellindex; -} \ No newline at end of file diff --git a/boundary.h b/boundary.h deleted file mode 100644 index caf24d275..000000000 --- a/boundary.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef BOUNDARY_H -#define BOUNDARY_H - -enum cell_boundary { - NEG_X = 101, - POS_X = 102, - NEG_Y = 103, - POS_Y = 104, - NEG_Z = 105, - POS_Z = 106, - NONE = 107, -}; - -double boundary_cross(struct packet *pkt_ptr, int *snext); -void change_cell(struct packet *pkt_ptr, int snext); - -#endif // BOUNDARY_H diff --git a/constants.h b/constants.h index f66b6cf53..fc1f7e2df 100644 --- a/constants.h +++ b/constants.h @@ -1,6 +1,8 @@ #ifndef CONSTANTS_H #define CONSTANTS_H +#include + /// fundamental constants constexpr double CLIGHT = 2.99792458e+10; /// Speed of light [cm/s] constexpr double CLIGHT_PROP = CLIGHT; // Speed of light for ray travel. Physically = CLIGHT but @@ -11,7 +13,7 @@ constexpr double LSUN = 3.826e+33; /// Solar luminosity [erg/s] constexpr double MH = 1.67352e-24; /// Mass of hydrogen atom [g] constexpr double ME = 9.1093897e-28; /// Mass of free electron [g] constexpr double QE = 4.80325E-10; /// elementary charge in cgs units [statcoulomb] -constexpr double PI = 3.1415926535987; +constexpr double PI = M_PI; constexpr double EV = 1.6021772e-12; /// eV to ergs [eV/erg] constexpr double MEV = 1.6021772e-6; /// MeV to ergs [MeV/erg] constexpr double DAY = 86400.0; /// day to seconds [s/day] @@ -38,8 +40,12 @@ constexpr double OSCSTRENGTHCONVERSION = 1.3473837e+21; constexpr double H_ionpot = 13.5979996 * EV; -constexpr int GRID_UNIFORM = 1; // Simple cuboidal cells. -constexpr int GRID_SPHERICAL1D = 2; // radial shells +enum gridtypes { + GRID_SPHERICAL1D = 1, // 1D radial shells (non-uniform dr) + GRID_CYLINDRICAL2D = 2, // 2D cylindrical grid with uniform dz, drcyl + GRID_CARTESIAN3D = 3 // 3D Cartesian cubic grid with uniform dx=dy=dz +}; +constexpr int GRID_UNIFORM = GRID_CARTESIAN3D; // deprecated alias for GRID_CARTESIAN3D // constant for van-Regemorter approximation. constexpr double C_0 = 5.465e-11; diff --git a/decay.cc b/decay.cc index 9ca16eddb..2015ebe5c 100644 --- a/decay.cc +++ b/decay.cc @@ -1,15 +1,19 @@ #include "decay.h" -#include // std::max +#include +#include #include #include #include #include #include +#include +#include #include #include #include #include +#include #include #include "atomic.h" @@ -22,8 +26,8 @@ namespace decay { -constexpr int Z_MAX = 119; -const char *elsymbols[1 + Z_MAX] = { +constexpr int Z_MAX = 118; +constexpr std::string_view elsymbols[Z_MAX + 1] = { "n", "H", "He", "Li", "Be", "B", "C", "N", "O", "F", "Ne", "Na", "Mg", "Al", "Si", "P", "S", "Cl", "Ar", "K", "Ca", "Sc", "Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn", "Ga", "Ge", "As", "Se", "Br", "Kr", "Rb", "Sr", "Y", "Zr", "Nb", "Mo", "Tc", "Ru", "Rh", "Pd", "Ag", "Cd", "In", "Sn", @@ -33,30 +37,82 @@ const char *elsymbols[1 + Z_MAX] = { "No", "Lr", "Rf", "Db", "Sg", "Bh", "Hs", "Mt", "Ds", "Rg", "Cn", "Uut", "Fl", "Uup", "Lv", "Uus", "Uuo"}; struct nuclide { - int z; // atomic number - int a; // mass number - double meanlife; // mean lifetime before decay [s] - double endecay_electron; // average energy per beta- decay in kinetic energy of emitted electons [erg] - double endecay_positron; // average energy per beta+ decay in kinetic energy of emitted positrons [erg] - double endecay_gamma; // average energy per decay in gamma rays [erg] - double endecay_alpha; // average energy per alpha decay in kinetic energy of alpha particles [erg] - double endecay_q[DECAYTYPE_COUNT]; // Q-value for decay (reactant minus product energy) of each decay type - double branchprobs[DECAYTYPE_COUNT]; // branch probabilities of each decay type + int z = -1; // atomic number + int a = -1; // mass number + double meanlife = -1; // mean lifetime before decay [s] + double endecay_electron = 0.; // average energy per beta- decay in kinetic energy of emitted electons [erg] + double endecay_positron = 0.; // average energy per beta+ decay in kinetic energy of emitted positrons [erg] + double endecay_gamma = 0.; // average energy per decay in gamma rays [erg] + double endecay_alpha = 0.; // average energy per alpha decay in kinetic energy of alpha particles [erg] + std::array endecay_q = { + 0.}; // Q-value (reactant minus product energy) for each decay type + std::array branchprobs = {0.}; // branch probability of each decay type }; std::vector nuclides; +constexpr auto decay_daughter_z(const int z_parent, const int /*a_parent*/, const int decaytype) -> int +// check if (z_parent, a_parent) is a parent of (z, a) +{ + assert_always(decaytype >= 0); + assert_always(decaytype < decaytypes::DECAYTYPE_COUNT); + + switch (static_cast(decaytype)) { + case decaytypes::DECAYTYPE_ALPHA: { + return z_parent - 2; // lose two protons and two neutrons + } + case decaytypes::DECAYTYPE_BETAPLUS: + case decaytypes::DECAYTYPE_ELECTRONCAPTURE: { + return z_parent - 1; // lose a proton, gain a neutron + } + case decaytypes::DECAYTYPE_BETAMINUS: { + return z_parent + 1; // lose a neutron, gain a proton + } + case decaytypes::DECAYTYPE_NONE: { + return -1; // no daughter + } + case decaytypes::DECAYTYPE_COUNT: { + assert_always(false); + } + } + return -1; // no daughter +} + +constexpr auto decay_daughter_a(const int /*z_parent*/, const int a_parent, const int decaytype) -> int +// check if (z_parent, a_parent) is a parent of (z, a) +{ + switch (static_cast(decaytype)) { + case decaytypes::DECAYTYPE_ALPHA: { + return a_parent - 4; // lose two protons and two neutrons + } + case decaytypes::DECAYTYPE_BETAPLUS: + case decaytypes::DECAYTYPE_ELECTRONCAPTURE: + case decaytypes::DECAYTYPE_BETAMINUS: { + return a_parent; // swap a neutron to proton or vice-versa + } + case decaytypes::DECAYTYPE_NONE: { + return -1; // no daughter + } + case decaytypes::DECAYTYPE_COUNT: { + assert_always(false); + } + } + return -1; // no daughter +} + // a decay path follows the contribution from an initial nuclear abundance // to another (daughter of last nuclide in decaypath) via decays // every different path within the network is considered, e.g. 56Ni -> 56Co -> 56Fe is separate to 56Ni -> 56Co struct decaypath { - int pathlength{}; std::vector z{}; // atomic number std::vector a{}; // mass number std::vector nucindex{}; // index into nuclides list std::vector decaytypes{}; std::vector lambdas{}; double branchproduct{}; // product of all branching factors along the path set by calculate_decaypath_branchproduct() + + [[nodiscard]] auto final_daughter_a() const -> int { return decay_daughter_a(z.back(), a.back(), decaytypes.back()); } + [[nodiscard]] auto final_daughter_z() const -> int { return decay_daughter_z(z.back(), a.back(), decaytypes.back()); } }; std::vector decaypaths; @@ -72,8 +128,8 @@ MPI_Win win_decaypath_energy_per_mass = MPI_WIN_NULL; auto get_num_nuclides() -> int { return nuclides.size(); } auto get_elname(const int z) -> const char * { - assert_always(z <= Z_MAX); - return elsymbols[z]; + assert_testmodeonly(z <= Z_MAX); + return &elsymbols[z].front(); } auto get_nuc_z(int nucindex) -> int { @@ -145,60 +201,11 @@ static void printout_nuclidemeanlife(const int z, const int a) { } } -constexpr auto decay_daughter_z(const int z_parent, const int /*a_parent*/, int decaytype) -> int -// check if (z_parent, a_parent) is a parent of (z, a) -{ - assert_always(decaytype >= 0); - assert_always(decaytype < DECAYTYPE_COUNT); - - switch (static_cast(decaytype)) { - case DECAYTYPE_ALPHA: { - return z_parent - 2; // lose two protons and two neutrons - } - case DECAYTYPE_BETAPLUS: - case DECAYTYPE_ELECTRONCAPTURE: { - return z_parent - 1; // lose a proton, gain a neutron - } - case DECAYTYPE_BETAMINUS: { - return z_parent + 1; // lose a neutron, gain a proton - } - case DECAYTYPE_NONE: { - return -1; // no daughter - } - case DECAYTYPE_COUNT: { - assert_always(false); - } - } - return -1; // no daughter -} - -constexpr auto decay_daughter_a(const int /*z_parent*/, const int a_parent, int decaytype) -> int -// check if (z_parent, a_parent) is a parent of (z, a) -{ - switch (static_cast(decaytype)) { - case DECAYTYPE_ALPHA: { - return a_parent - 4; // lose two protons and two neutrons - } - case DECAYTYPE_BETAPLUS: - case DECAYTYPE_ELECTRONCAPTURE: - case DECAYTYPE_BETAMINUS: { - return a_parent; // swap a neutron to proton or vice-versa - } - case DECAYTYPE_NONE: { - return -1; // no daughter - } - case DECAYTYPE_COUNT: { - assert_always(false); - } - } - return -1; // no daughter -} - static auto get_nuc_decaybranchprob(const int nucindex, const int decaytype) -> double { assert_testmodeonly(nucindex >= 0); assert_testmodeonly(nucindex < get_num_nuclides()); assert_testmodeonly(decaytype >= 0); - assert_testmodeonly(decaytype < DECAYTYPE_COUNT); + assert_testmodeonly(decaytype < decaytypes::DECAYTYPE_COUNT); return nuclides[nucindex].branchprobs[decaytype]; } @@ -211,14 +218,9 @@ static auto nuc_is_parent(const int z_parent, const int a_parent, const int z, c { assert_testmodeonly(nuc_exists(z_parent, a_parent)); // each radioactive nuclide is limited to one daughter nuclide - for (int dectypeindex = 0; dectypeindex < DECAYTYPE_COUNT; dectypeindex++) { - if (decay_daughter_z(z_parent, a_parent, dectypeindex) == z && - decay_daughter_a(z_parent, a_parent, dectypeindex) == a && - get_nuc_decaybranchprob(z_parent, a_parent, dectypeindex) > 0.) { - return true; - } - } - return false; + return std::ranges::any_of(all_decaytypes, [=](const auto decaytype) { + return decay_daughter_z(z_parent, a_parent, decaytype) == z && decay_daughter_a(z_parent, a_parent, decaytype) == a; + }); } auto nucdecayenergygamma(int nucindex) -> double @@ -239,19 +241,19 @@ static auto nucdecayenergyparticle(const int nucindex, const int decaytype) -> d // depending on the relevant decay type (but not including neutrinos) { assert_testmodeonly(decaytype >= 0); - assert_testmodeonly(decaytype < DECAYTYPE_COUNT); + assert_testmodeonly(decaytype < decaytypes::DECAYTYPE_COUNT); switch (decaytype) { - case DECAYTYPE_ALPHA: { + case decaytypes::DECAYTYPE_ALPHA: { return nuclides[nucindex].endecay_alpha; } - case DECAYTYPE_BETAPLUS: { + case decaytypes::DECAYTYPE_BETAPLUS: { return nuclides[nucindex].endecay_positron; } - case DECAYTYPE_ELECTRONCAPTURE: { + case decaytypes::DECAYTYPE_ELECTRONCAPTURE: { return 0.; } - case DECAYTYPE_BETAMINUS: { + case decaytypes::DECAYTYPE_BETAMINUS: { return nuclides[nucindex].endecay_electron; } default: { @@ -264,17 +266,16 @@ static auto nucdecayenergytotal(const int z, const int a) -> double // average energy (erg) per decay in the form of gammas and particles [erg] { const int nucindex = get_nucindex(z, a); - double endecay = 0.; - endecay += nuclides[nucindex].endecay_gamma; - for (int decaytype = 0; decaytype < DECAYTYPE_COUNT; decaytype++) { - endecay += nucdecayenergyparticle(nucindex, decaytype) * get_nuc_decaybranchprob(nucindex, decaytype); - } + const auto endecay_particles = std::accumulate( + all_decaytypes.cbegin(), all_decaytypes.cend(), 0., [nucindex](const double ensum, const auto &decaytype) { + return ensum + nucdecayenergyparticle(nucindex, decaytype) * get_nuc_decaybranchprob(nucindex, decaytype); + }); - return endecay; + return nuclides[nucindex].endecay_gamma + endecay_particles; } static auto nucdecayenergy(int nucindex, int decaytype) -> double -// contributed energy release per decay [erg] for decaytype (e.g. DECAYTYPE_BETAPLUS) +// contributed energy release per decay [erg] for decaytype (e.g. decaytypes::DECAYTYPE_BETAPLUS) // (excludes neutrinos!) { const double endecay = nuclides[nucindex].endecay_gamma + nucdecayenergyparticle(nucindex, decaytype); @@ -286,57 +287,58 @@ static auto nucdecayenergyqval(int nucindex, int decaytype) -> double { return nuclides[nucindex].endecay_q[decaytype]; } -auto nucmass(int z, int a) -> double { - assert_testmodeonly(z > 0); - assert_testmodeonly(a >= z); - - return a * MH; - - // return nuclides[nucindex].amass; -} - -static auto get_num_decaypaths() -> int { return decaypaths.size(); } +static auto get_num_decaypaths() -> int { return static_cast(decaypaths.size()); } -static auto get_decaypathlength(int decaypathindex) -> int { return decaypaths[decaypathindex].pathlength; } +static auto get_decaypathlength(const decaypath &dpath) -> int { return static_cast(dpath.z.size()); } +static auto get_decaypathlength(int decaypathindex) -> int { return get_decaypathlength(decaypaths[decaypathindex]); } -static auto calculate_decaypath_branchproduct(int decaypathindex) -> double +static auto calculate_decaypath_branchproduct(const decaypath &decaypath) -> double // return the product of all branching factors in the decay path { double branchprod = 1.; - for (int i = 0; i < get_decaypathlength(decaypathindex); i++) { - branchprod = branchprod * get_nuc_decaybranchprob(decaypaths[decaypathindex].nucindex[i], - decaypaths[decaypathindex].decaytypes[i]); + for (int i = 0; i < get_decaypathlength(decaypath); i++) { + branchprod = branchprod * get_nuc_decaybranchprob(decaypath.nucindex[i], decaypath.decaytypes[i]); } return branchprod; } -static auto get_decaypath_lastnucdecayenergy(const int decaypathindex) -> double +static auto calculate_decaypath_branchproduct(int decaypathindex) -> double +// return the product of all branching factors in the decay path +{ + return calculate_decaypath_branchproduct(decaypaths[decaypathindex]); +} + +static auto get_decaypath_lastnucdecayenergy(const decaypath &dpath) -> double // a decaypath's energy is the decay energy of the last nuclide and decaytype in the chain { - const int nucindex_end = decaypaths[decaypathindex].nucindex[get_decaypathlength(decaypathindex) - 1]; - const int decaytype_end = decaypaths[decaypathindex].decaytypes[get_decaypathlength(decaypathindex) - 1]; + const int nucindex_end = dpath.nucindex.back(); + const int decaytype_end = dpath.decaytypes.back(); return nucdecayenergy(nucindex_end, decaytype_end); } +static auto get_decaypath_lastnucdecayenergy(const int decaypathindex) -> double { + return get_decaypath_lastnucdecayenergy(decaypaths[decaypathindex]); +} + static void printout_decaytype(const int decaytype) { switch (decaytype) { - case DECAYTYPE_ALPHA: { + case decaytypes::DECAYTYPE_ALPHA: { printout("alpha"); break; } - case DECAYTYPE_BETAPLUS: { + case decaytypes::DECAYTYPE_BETAPLUS: { printout("beta+"); break; } - case DECAYTYPE_ELECTRONCAPTURE: { + case decaytypes::DECAYTYPE_ELECTRONCAPTURE: { printout("ec"); break; } - case DECAYTYPE_BETAMINUS: { + case decaytypes::DECAYTYPE_BETAMINUS: { printout("beta-"); break; } - case DECAYTYPE_NONE: { + case decaytypes::DECAYTYPE_NONE: { printout("none"); break; } @@ -347,27 +349,25 @@ static void printout_decaytype(const int decaytype) { static void printout_decaypath(const int decaypathindex) { assert_always(!decaypaths.empty()); + const auto &decaypath = decaypaths[decaypathindex]; printout(" decaypath %d: ", decaypathindex); - printout_nuclidename(decaypaths[decaypathindex].z[0], decaypaths[decaypathindex].a[0]); - printout_nuclidemeanlife(decaypaths[decaypathindex].z[0], decaypaths[decaypathindex].a[0]); - - for (int i = 1; i < get_decaypathlength(decaypathindex); i++) { - printout(" -> "); - printout_decaytype(decaypaths[decaypathindex].decaytypes[i - 1]); - printout(" -> "); - printout_nuclidename(decaypaths[decaypathindex].z[i], decaypaths[decaypathindex].a[i]); - printout_nuclidemeanlife(decaypaths[decaypathindex].z[i], decaypaths[decaypathindex].a[i]); + + for (int i = 0; i < get_decaypathlength(decaypathindex); i++) { + printout_nuclidename(decaypath.z[i], decaypath.a[i]); + printout_nuclidemeanlife(decaypath.z[i], decaypath.a[i]); + + if (decaypath.decaytypes[i] != DECAYTYPE_NONE) { + printout(" -> "); + printout_decaytype(decaypath.decaytypes[i]); + printout(" -> "); + } + } + + // if the last nuclide is unstable, print its daughter nucleus + if (decaypath.decaytypes.back() != DECAYTYPE_NONE) { + printout_nuclidename(decaypath.final_daughter_z(), decaypath.final_daughter_a()); + printout_nuclidemeanlife(decaypath.final_daughter_z(), decaypath.final_daughter_a()); } - const int last_z = decaypaths[decaypathindex].z[get_decaypathlength(decaypathindex) - 1]; - const int last_a = decaypaths[decaypathindex].a[get_decaypathlength(decaypathindex) - 1]; - const int last_decaytype = decaypaths[decaypathindex].decaytypes[get_decaypathlength(decaypathindex) - 1]; - const int end_z = decay_daughter_z(last_z, last_a, last_decaytype); - const int end_a = decay_daughter_a(last_z, last_a, last_decaytype); - printout(" -> "); - printout_decaytype(last_decaytype); - printout(" -> "); - printout_nuclidename(end_z, end_a); - printout_nuclidemeanlife(end_z, end_a); printout("\n"); } @@ -377,15 +377,12 @@ static void extend_lastdecaypath() // to get decaypaths from all descendants { const int startdecaypathindex = decaypaths.size() - 1; - const int last_z = decaypaths[startdecaypathindex].z[get_decaypathlength(startdecaypathindex) - 1]; - const int last_a = decaypaths[startdecaypathindex].a[get_decaypathlength(startdecaypathindex) - 1]; - const int dectypeindex = decaypaths[startdecaypathindex].decaytypes[get_decaypathlength(startdecaypathindex) - 1]; - const int daughter_z = decay_daughter_z(last_z, last_a, dectypeindex); - const int daughter_a = decay_daughter_a(last_z, last_a, dectypeindex); + const int daughter_z = decaypaths[startdecaypathindex].final_daughter_z(); + const int daughter_a = decaypaths[startdecaypathindex].final_daughter_a(); if (nuc_exists(daughter_z, daughter_a)) { const int daughter_nucindex = get_nucindex(daughter_z, daughter_a); - for (int dectypeindex2 = 0; dectypeindex2 < DECAYTYPE_COUNT; dectypeindex2++) { + for (enum decaytypes dectypeindex2 : all_decaytypes) { if (get_nuc_decaybranchprob(daughter_nucindex, dectypeindex2) == 0.) { continue; } @@ -398,11 +395,9 @@ static void extend_lastdecaypath() } } - const int newpathlength = get_decaypathlength(startdecaypathindex) + 1; decaypaths.push_back(decaypaths[startdecaypathindex]); const int lastindex = decaypaths.size() - 1; - decaypaths[lastindex].pathlength = newpathlength; decaypaths[lastindex].z.push_back(daughter_z); decaypaths[lastindex].a.push_back(daughter_a); decaypaths[lastindex].nucindex.push_back(daughter_nucindex); @@ -413,51 +408,60 @@ static void extend_lastdecaypath() } } -constexpr auto operator<(const struct decaypath &d1, const struct decaypath &d2) -> bool +static auto operator<(const struct decaypath &d1, const struct decaypath &d2) -> bool // true if d1 < d2 -// order the chains in the same way as when the search moved up from the descendant -// instead of down from the ancestor, for ease of test comparison -// chains are sorted by mass number of first, second, third, etc position in chain +// chains are sorted by mass number, then atomic number, then length { - const int smallestpathlength = std::min(d1.pathlength, d2.pathlength); - bool matchingoverlap = true; + const int d1_length = get_decaypathlength(d1); + const int d2_length = get_decaypathlength(d2); + const int smallestpathlength = std::min(d1_length, d2_length); for (int i = 0; i < smallestpathlength; i++) { - const int d1pos = d1.pathlength - 1 - i; - // assert_always(d1pos >= 0); - // assert_always(d1pos < d1.pathlength); - const int d2pos = d2.pathlength - 1 - i; - // assert_always(d2pos >= 0); - // assert_always(d2pos < d2.pathlength); - // if (get_nucindex(d1.z[d1pos], d1.a[d1pos]) < get_nucindex(d2.z[d2pos], d2.a[d2pos])) - if (d1.a[d1pos] < d2.a[d2pos]) { + if (d1.a[i] < d2.a[i]) { return true; } - if (d1.a[d1pos] == d2.a[d2pos] && d1.z[d1pos] < d2.z[d2pos]) { + if (d1.a[i] > d2.a[i]) { + return false; + } + if (d1.z[i] < d2.z[i]) { return true; } - if (d1.a[d1pos] != d2.a[d2pos] || d1.z[d1pos] != d2.z[d2pos]) { - matchingoverlap = false; + if (d1.z[i] > d2.z[i]) { + return false; } } // one is an extension of the other - return matchingoverlap && d1.pathlength < d2.pathlength; + return d1_length < d2_length; } -static void find_decaypaths() { +static void find_decaypaths(const std::vector &custom_zlist, const std::vector &custom_alist, + std::vector &standard_nuclides) { + decaypaths.clear(); for (int startnucindex = 0; startnucindex < get_num_nuclides(); startnucindex++) { const int z = get_nuc_z(startnucindex); const int a = get_nuc_a(startnucindex); - for (int dectypeindex = 0; dectypeindex < DECAYTYPE_COUNT; dectypeindex++) { - if (get_nuc_decaybranchprob(startnucindex, dectypeindex) == 0. || get_meanlife(startnucindex) <= 0.) { + for (const auto decaytype : all_decaytypes) { + if (get_nuc_decaybranchprob(startnucindex, decaytype) == 0. || get_meanlife(startnucindex) <= 0.) { + continue; + } + bool is_custom_nuclide = false; + for (size_t i = 0; i < custom_zlist.size(); i++) { + if ((z == custom_zlist[i]) && (a == custom_alist[i])) { + is_custom_nuclide = true; + break; + } + } + // skip path if it doesn't start from a nuclide in the custom or standard input lists + if (!is_custom_nuclide && !std::ranges::any_of(standard_nuclides, [z, a](const auto &stdnuc) { + return (z == stdnuc.z) && (a == stdnuc.a); + })) { continue; } - decaypaths.push_back({.pathlength = 1, - .z = std::vector(1, z), + decaypaths.push_back({.z = std::vector(1, z), .a = std::vector(1, a), .nucindex = std::vector(1, startnucindex), - .decaytypes = std::vector(1, dectypeindex)}); + .decaytypes = std::vector(1, decaytype)}); extend_lastdecaypath(); // take this single step chain and find all descendants } @@ -465,23 +469,71 @@ static void find_decaypaths() { std::sort(decaypaths.begin(), decaypaths.end()); - for (int decaypathindex = 0; decaypathindex < get_num_decaypaths(); decaypathindex++) { - int const decaypathlength = get_decaypathlength(decaypathindex); - - for (int i = 0; i < decaypathlength; i++) { - const double meanlife = get_meanlife(decaypaths[decaypathindex].nucindex[i]); - - // last nuclide might be stable (meanlife <= 0.) - assert_always(meanlife > 0. || (i == decaypathlength - 1)); // only the last nuclide can be stable - const double lambda = (meanlife > 0.) ? 1. / meanlife : 0.; - - decaypaths[decaypathindex].lambdas.push_back(lambda); - } - - // the nuclide past the end of the path is a used as a sink, so treat it as stable (even if it's not) - decaypaths[decaypathindex].lambdas.push_back(0.); + for (auto &decaypath : decaypaths) { + // all nuclei in the path (except for the last one, which is allowed to be stable) must have a mean life >0 + assert_always(std::all_of(decaypath.nucindex.cbegin(), decaypath.nucindex.cend() - 1, + [](const auto nucindex) { return get_meanlife(nucindex) > 0.; })); + + // convert mean lifetimes to decay constants + decaypath.lambdas.resize(decaypath.nucindex.size()); + std::transform(decaypath.nucindex.cbegin(), decaypath.nucindex.cend(), decaypath.lambdas.begin(), + [](const auto nucindex) { + const double meanlife = get_meanlife(nucindex); + // last nuclide might be stable (meanlife <= 0.) + const double lambda = (meanlife > 0.) ? 1. / meanlife : 0.; + return lambda; + }); + + // the nuclide one past the end of the path is a used as a sink, so treat it as stable (even if it's not) + decaypath.lambdas.push_back(0.); + + decaypath.branchproduct = calculate_decaypath_branchproduct(decaypath); + } + decaypaths.shrink_to_fit(); +} - decaypaths[decaypathindex].branchproduct = calculate_decaypath_branchproduct(decaypathindex); +static void filter_unused_nuclides(const std::vector &custom_zlist, const std::vector &custom_alist, + std::vector &standard_nuclides) { + // remove nuclides that are not a standard or custom input-specified nuclide, or connected to these by decays + nuclides.erase( + std::remove_if(nuclides.begin(), nuclides.end(), + [&](const auto &nuc) { + // keep nucleus if it is in the standard list + if (std::ranges::any_of(standard_nuclides, [&](const auto &stdnuc) { + return (stdnuc.z == nuc.z) && (stdnuc.a == nuc.a); + })) { + return false; + } + // keep nucleus if it is in the custom list + for (size_t i = 0; i < custom_zlist.size(); i++) { + if ((nuc.z == custom_zlist[i]) && (nuc.a == custom_alist[i])) { + return false; + } + } + + // keep if it is connected by decays to one of the standard or custom input-specified nuclides + for (const auto &decaypath : decaypaths) { + if (decaypath.final_daughter_z() == nuc.z && decaypath.final_daughter_a() == nuc.a) { + return false; + } + + for (size_t i = 0; i < decaypath.z.size(); i++) { + if (decaypath.z[i] == nuc.z && decaypath.a[i] == nuc.a) { + // decay path starts with input nuc and nuc is in the decay path, so keep it + return false; + }; + } + } + printout("removing unused nuclide (Z=%d)%s-%d\n", nuc.z, get_elname(nuc.z), nuc.a); + return true; + }), + nuclides.end()); + nuclides.shrink_to_fit(); + + // update the nuclide indicies in the decay paths after we possibly removed some nuclides + for (auto &decaypath : decaypaths) { + std::transform(decaypath.z.cbegin(), decaypath.z.cend(), decaypath.a.cbegin(), decaypath.nucindex.begin(), + [](const auto z, const auto a) { return get_nucindex(z, a); }); } } @@ -491,7 +543,7 @@ auto get_nucstring_z(const std::string &strnuc) -> int std::string elcode = strnuc; elcode.erase(std::remove_if(elcode.begin(), elcode.end(), &isdigit), elcode.end()); - for (int z = 1; z <= Z_MAX; z++) { + for (int z = 0; z <= Z_MAX; z++) { if (strcmp(elcode.c_str(), get_elname(z)) == 0) // first to letters match el symbol { return z; @@ -521,82 +573,68 @@ auto get_nucstring_a(const std::string &strnuc) -> int return a; } -void init_nuclides(std::vector custom_zlist, std::vector custom_alist) { +void init_nuclides(const std::vector &custom_zlist, const std::vector &custom_alist) { + // add all nuclides and decays, and later trim any irrelevant ones (not connected to input-specified nuclei) later + assert_always(custom_zlist.size() == custom_alist.size()); - struct nuclide default_nuclide {}; - default_nuclide.z = -1; - default_nuclide.a = -1; - default_nuclide.meanlife = -1; - default_nuclide.endecay_electron = 0.; - default_nuclide.endecay_positron = 0.; - default_nuclide.endecay_gamma = 0.; - default_nuclide.endecay_alpha = 0.; - for (int dectypeindex = 0; dectypeindex < DECAYTYPE_COUNT; dectypeindex++) { - default_nuclide.branchprobs[dectypeindex] = 0.; - default_nuclide.endecay_q[dectypeindex] = 0.; - } + // Ni57 + nuclides.push_back({.z = 28, .a = 57, .meanlife = 51.36 * 60}); + nuclides.back().endecay_positron = 0.354 * MEV; + nuclides.back().branchprobs[DECAYTYPE_BETAPLUS] = 0.436; + nuclides.back().branchprobs[DECAYTYPE_ELECTRONCAPTURE] = 1. - 0.436; - nuclides.push_back(default_nuclide); - nuclides.back().z = 28; // Ni57 - nuclides.back().a = 57; - nuclides.back().meanlife = 51.36 * 60; - nuclides.back().endecay_positron = 0.354 * MEV * 0.436; - nuclides.back().branchprobs[DECAYTYPE_BETAPLUS] = 1.; - // nuclides.back().branchprobs[DECAYTYPE_BETAPLUS] = 0.436; - // nuclides.back().branchprobs[DECAYTYPE_ELECTRONCAPTURE] = 1. - 0.436; - - nuclides.push_back(default_nuclide); - nuclides.back().z = 28; // Ni56 - nuclides.back().a = 56; - nuclides.back().meanlife = 8.80 * DAY; + // Ni56 + nuclides.push_back({.z = 28, .a = 56, .meanlife = 8.80 * DAY}); nuclides.back().branchprobs[DECAYTYPE_ELECTRONCAPTURE] = 1.; - nuclides.push_back(default_nuclide); - nuclides.back().z = 27; // Co56 - nuclides.back().a = 56; - nuclides.back().meanlife = 113.7 * DAY; - // old method: move BETAPLUS branching factor into average positron energy - nuclides.back().endecay_positron = 0.63 * MEV * 0.19; - nuclides.back().branchprobs[DECAYTYPE_BETAPLUS] = 1.; - // should produce the same results if everything is done correctly - // nuclides.back().endecay_positron = 0.63 * MEV; - // nuclides.back().branchprobs[DECAYTYPE_BETAPLUS] = 0.19; - // nuclides.back().branchprobs[DECAYTYPE_ELECTRONCAPTURE] = 0.81; - - nuclides.push_back(default_nuclide); - nuclides.back().z = 24; // Cr48 - nuclides.back().a = 48; - nuclides.back().meanlife = 1.29602 * DAY; + // Co56 + nuclides.push_back({.z = 27, .a = 56, .meanlife = 113.7 * DAY}); + nuclides.back().endecay_positron = 0.63 * MEV; + nuclides.back().branchprobs[DECAYTYPE_BETAPLUS] = 0.19; + nuclides.back().branchprobs[DECAYTYPE_ELECTRONCAPTURE] = 1 - 0.19; + + // Cr48 + nuclides.push_back({.z = 24, .a = 48, .meanlife = 1.29602 * DAY}); nuclides.back().branchprobs[DECAYTYPE_ELECTRONCAPTURE] = 1.; - nuclides.push_back(default_nuclide); - nuclides.back().z = 23; // V48 - nuclides.back().a = 48; - nuclides.back().meanlife = 23.0442 * DAY; + // V48 + nuclides.push_back({.z = 23, .a = 48, .meanlife = 23.0442 * DAY}); nuclides.back().endecay_positron = 0.290 * MEV * 0.499; nuclides.back().branchprobs[DECAYTYPE_BETAPLUS] = 1.; - nuclides.push_back(default_nuclide); - nuclides.back().z = 27; // Co57 - nuclides.back().a = 57; - nuclides.back().meanlife = 392.03 * DAY; + // Co57 + nuclides.push_back({.z = 27, .a = 57, .meanlife = 392.03 * DAY}); nuclides.back().branchprobs[DECAYTYPE_ELECTRONCAPTURE] = 1.; - nuclides.push_back(default_nuclide); - nuclides.back().z = 26; // Fe52 - nuclides.back().a = 52; - nuclides.back().meanlife = 0.497429 * DAY; + // Fe52 + nuclides.push_back({.z = 26, .a = 52, .meanlife = 0.497429 * DAY}); nuclides.back().branchprobs[DECAYTYPE_ELECTRONCAPTURE] = 1.; - nuclides.push_back(default_nuclide); - nuclides.back().z = 25; // Mn52 - nuclides.back().a = 52; - nuclides.back().meanlife = 0.0211395 * DAY; + // Mn52 + nuclides.push_back({.z = 25, .a = 52, .meanlife = 0.0211395 * DAY}); nuclides.back().branchprobs[DECAYTYPE_ELECTRONCAPTURE] = 1.; - if (!custom_alist.empty()) { - std::ifstream fbetaminus("betaminusdecays.txt"); + auto standard_nuclides = nuclides; + + // any nuclides in the custom list that are not in the standard list need beta and alpha decay data + + bool use_custom_nuclides = false; + for (size_t i = 0; i < custom_zlist.size(); i++) { + if (custom_zlist[i] < 0 || custom_alist[i] < 0) { + continue; + } + const bool in_std_list = std::ranges::any_of(standard_nuclides, [=](const auto &stdnuc) { + return (custom_zlist[i] == stdnuc.z) && (custom_alist[i] == stdnuc.a); + }); + if (!in_std_list) { + use_custom_nuclides = true; + break; + } + } + + if (use_custom_nuclides) { + auto fbetaminus = fstream_required("betaminusdecays.txt", std::ios::in); assert_always(fbetaminus.is_open()); std::string line; while (get_noncommentline(fbetaminus, line)) { @@ -611,31 +649,18 @@ void init_nuclides(std::vector custom_zlist, std::vector custom_alist) double tau_sec = 0.; std::stringstream(line) >> a >> z >> q_mev >> e_gamma_mev >> e_elec_mev >> e_neutrino >> tau_sec; - bool keeprow = false; // keep if the mass number matches one of the input nuclides - for (int const i : custom_alist) { - if (i == a) { - keeprow = true; - break; - } - } - if (keeprow) { - assert_always(!nuc_exists(z, a)); - nuclides.push_back(default_nuclide); - nuclides.back().z = z; - nuclides.back().a = a; - nuclides.back().meanlife = tau_sec; - nuclides.back().branchprobs[DECAYTYPE_BETAMINUS] = 1.; - nuclides.back().endecay_q[DECAYTYPE_BETAMINUS] = q_mev * MEV; - nuclides.back().endecay_electron = e_elec_mev * MEV; - nuclides.back().endecay_gamma = e_gamma_mev * MEV; - // printout("betaminus file: Adding (Z=%d)%s-%d endecay_electron %g endecay_gamma %g tau_s %g\n", - // z, get_elname(z), a, e_elec_mev, e_gamma_mev, tau_sec); - assert_always(e_elec_mev >= 0.); - } + assert_always(!nuc_exists(z, a)); + nuclides.push_back({.z = z, .a = a, .meanlife = tau_sec}); + nuclides.back().branchprobs[DECAYTYPE_BETAMINUS] = 1.; + nuclides.back().endecay_q[DECAYTYPE_BETAMINUS] = q_mev * MEV; + nuclides.back().endecay_electron = e_elec_mev * MEV; + nuclides.back().endecay_gamma = e_gamma_mev * MEV; + // printout("betaminus file: Adding (Z=%d)%s-%d endecay_electron %g endecay_gamma %g tau_s %g\n", + // z, get_elname(z), a, e_elec_mev, e_gamma_mev, tau_sec); + assert_always(e_elec_mev >= 0.); } - fbetaminus.close(); - std::ifstream falpha("alphadecays.txt"); + auto falpha = fstream_required("alphadecays.txt", std::ios::in); assert_always(falpha.is_open()); while (get_noncommentline(falpha, line)) { // columns: # A, Z, branch_alpha, branch_beta, halflife[s], Q_total_alphadec[MeV], Q_total_betadec[MeV], @@ -653,22 +678,14 @@ void init_nuclides(std::vector custom_zlist, std::vector custom_alist) std::stringstream(line) >> a >> z >> branch_alpha >> branch_beta >> halflife >> Q_total_alphadec >> Q_total_betadec >> e_alpha_mev >> e_gamma_mev >> e_beta_mev; - bool const keeprow = ((branch_alpha > 0. || branch_beta > 0.) && halflife > 0.); + const bool keeprow = ((branch_alpha > 0. || branch_beta > 0.) && halflife > 0.); if (keeprow) { const double tau_sec = halflife / log(2); int alphanucindex = -1; if (nuc_exists(z, a)) { alphanucindex = get_nucindex(z, a); - // printout("compare z %d a %d e_gamma_mev1 %g e_gamma_mev2 %g\n", z, a, nucdecayenergygamma(z, a) / MEV, - // e_gamma_mev); printout("compare z %d a %d tau1 %g tau2 %g\n", z, a, get_meanlife(z, a), tau_sec); - // printout("compare z %d a %d e_beta_mev1 %g e_beta_mev2 %g\n", z, a, nuclides[get_nucindex(z, - // a)].endecay_positron / MEV, e_beta_mev); } else { - nuclides.push_back(default_nuclide); - nuclides.back().z = z; - nuclides.back().a = a; - nuclides.back().meanlife = tau_sec; - nuclides.back().endecay_gamma = e_gamma_mev * MEV; + nuclides.push_back({.z = z, .a = a, .meanlife = tau_sec, .endecay_gamma = e_gamma_mev * MEV}); alphanucindex = nuclides.size() - 1; } nuclides[alphanucindex].endecay_alpha = e_alpha_mev * MEV; @@ -681,45 +698,33 @@ void init_nuclides(std::vector custom_zlist, std::vector custom_alist) // z, get_elname(z), a, e_alpha_mev, e_gamma_mev, tau_sec); } } - falpha.close(); } + // add any extra nuclides that were specified but not in the decay data files for (int i = 0; i < static_cast(custom_alist.size()); i++) { const int z = custom_zlist[i]; const int a = custom_alist[i]; if (!nuc_exists(z, a)) { // printout("Adding Z %d A %d with no decay data (assuming stable)\n", z, a); - nuclides.push_back(default_nuclide); - nuclides.back().z = z; - nuclides.back().a = a; - nuclides.back().meanlife = -1; + nuclides.push_back({.z = z, .a = a, .meanlife = -1}); } } - // TESTING: REMOVE - // for (int i = 0; i < get_num_nuclides(); i++) - // { - // for (int dectypeindex = 0; dectypeindex < DECAYTYPE_COUNT; dectypeindex++) - // { - // nuclides[i].branchprobs[dectypeindex] *= 1e-4; - // nuclides[i].endecay_gamma = 0.; - // } - // } - - printout("init_nuclides: num_nuclides %d\n", get_num_nuclides()); + printout("Number of nuclides before filtering: %d\n", get_num_nuclides()); + find_decaypaths(custom_zlist, custom_alist, standard_nuclides); + filter_unused_nuclides(custom_zlist, custom_alist, standard_nuclides); - /// Read in data for gamma ray lines and make a list of them in energy order. - gammapkt::init_gamma_linelist(); + printout("Number of nuclides: %d\n", get_num_nuclides()); - find_decaypaths(); + const int maxdecaypathlength = std::accumulate( + decaypaths.cbegin(), decaypaths.cend(), 0, + [](const int maxlen, const auto decaypath) { return std::max(maxlen, get_decaypathlength(decaypath)); }); - int maxdecaypathlength = 0; - for (int decaypathindex = 0; decaypathindex < get_num_decaypaths(); decaypathindex++) { - // printout_decaypath(decaypathindex); - maxdecaypathlength = std::max(maxdecaypathlength, get_decaypathlength(decaypathindex)); - } printout("Number of decay paths: %d (max length %d)\n", get_num_decaypaths(), maxdecaypathlength); + /// Read in data for gamma ray lines and make a list of them in energy order. + gammapkt::init_gamma_linelist(); + // TODO: generalise this to all included nuclides printout("decayenergy(NI56), decayenergy(CO56), decayenergy_gamma(CO56): %g, %g, %g\n", nucdecayenergytotal(28, 56) / MEV, nucdecayenergytotal(27, 56) / MEV, nucdecayenergygamma(27, 56) / MEV); @@ -747,16 +752,17 @@ static auto sample_decaytime(const int decaypathindex, const double tdecaymin, c return tdecay; } -static auto calculate_decaychain(const double firstinitabund, std::vector &lambdas, const int num_nuclides, - const double timediff, bool useexpansionfactor) -> double { +static constexpr auto calculate_decaychain(const double firstinitabund, const std::vector &lambdas, + const int num_nuclides, const double timediff, const bool useexpansionfactor) + -> double { // calculate final number abundance from multiple decays, e.g., Ni56 -> Co56 -> Fe56 (nuc[0] -> nuc[1] -> nuc[2]) // the top nuclide initial abundance is set and the chain-end abundance is returned (all intermediates nuclides // are assumed to start with zero abundance) // note: first and last can be nuclide can be the same if num_nuclides==1, reducing to simple decay formula // // timediff: time elapsed since firstinitabund was true [seconds] - // numnuclides: number of items in meanlifetimes to use - // meanlifetimes: array of mean lifetimes for nuc[0]..nuc[num_nuclides-1] [seconds] + // numnuclides: number of items in lambdas to use + // lambdas: array of 1/(mean lifetime) for nuc[0]..nuc[num_nuclides-1] [seconds^-1] // useexpansionfactor: if true, return a modified 'abundance' at the end of the chain, with a weighting factor // accounting for photon energy loss from expansion since the decays occured // (This is needed to get the initial temperature) @@ -809,13 +815,12 @@ static auto get_nuc_massfrac(const int modelgridindex, const int z, const int a, // decay chains include all paths from radionuclides to other radionuclides (including trivial size-one chains) double nuctotal = 0.; // abundance or decay rate, depending on mode parameter - for (int decaypathindex = 0; decaypathindex < get_num_decaypaths(); decaypathindex++) { - const int z_end = decaypaths[decaypathindex].z[get_decaypathlength(decaypathindex) - 1]; - const int a_end = decaypaths[decaypathindex].a[get_decaypathlength(decaypathindex) - 1]; + for (const auto &decaypath : decaypaths) { + const int z_end = decaypath.z.back(); + const int a_end = decaypath.a.back(); // match 4He abundance to alpha decay of any nucleus (no continue), otherwise check daughter nuclide matches - if (z != 2 || a != 4 || - decaypaths[decaypathindex].decaytypes[get_decaypathlength(decaypathindex) - 1] != DECAYTYPE_ALPHA) { + if (z != 2 || a != 4 || decaypath.decaytypes.back() != decaytypes::DECAYTYPE_ALPHA) { if (nuc_exists_z_a && (z_end != z || a_end != a)) // requested nuclide is in network, so match last nuc in chain { continue; @@ -827,9 +832,9 @@ static auto get_nuc_massfrac(const int modelgridindex, const int z, const int a, } } - const int z_top = decaypaths[decaypathindex].z[0]; - const int a_top = decaypaths[decaypathindex].a[0]; - const int nucindex_top = decaypaths[decaypathindex].nucindex[0]; + const int z_top = decaypath.z[0]; + const int a_top = decaypath.a[0]; + const int nucindex_top = decaypath.nucindex[0]; const double top_initabund = grid::get_modelinitradioabund(modelgridindex, nucindex_top) / nucmass(z_top, a_top); assert_always(top_initabund >= 0.); @@ -837,20 +842,19 @@ static auto get_nuc_massfrac(const int modelgridindex, const int z, const int a, continue; } - int const decaypathlength = get_decaypathlength(decaypathindex); + const int decaypathlength = get_decaypathlength(decaypath); int fulldecaypathlength = decaypathlength; // if the nuclide is out of network, it's one past the end of the chain - if (!nuc_exists_z_a || - (z == 2 && a == 4 && - decaypaths[decaypathindex].decaytypes[get_decaypathlength(decaypathindex) - 1] == DECAYTYPE_ALPHA)) { + // or if we're counting alpha particles and the last decaytype is alpha, then the alpha sink is one past the end + if (!nuc_exists_z_a || (z == 2 && a == 4 && decaypath.decaytypes.back() == decaytypes::DECAYTYPE_ALPHA)) { fulldecaypathlength = decaypathlength + 1; } - const double massfraccontrib = (decaypaths[decaypathindex].branchproduct * - calculate_decaychain(top_initabund, decaypaths[decaypathindex].lambdas, - fulldecaypathlength, t_afterinit, false) * - nucmass(z, a)); + const double massfraccontrib = + (decaypath.branchproduct * + calculate_decaychain(top_initabund, decaypath.lambdas, fulldecaypathlength, t_afterinit, false) * + nucmass(z, a)); // assert_always(massfraccontrib >= 0.); nuctotal += massfraccontrib; } @@ -957,32 +961,20 @@ auto get_endecay_per_ejectamass_t0_to_time_withexpansion(const int modelgridinde // the photon energy loss due to expansion between time of decays and tstart (equation 18 of Lucy 2005) { double tot_endecay = 0.; - for (int decaypathindex = 0; decaypathindex < get_num_decaypaths(); decaypathindex++) { - if (get_endecay_to_tinf_per_ejectamass_at_time(modelgridindex, decaypathindex, grid::get_t_model()) <= 0.) { - // skip unused chains - continue; - } - // printout_decaypath(decaypathindex); - // get_endecay_per_ejectamass_t0_to_time_withexpansion_chain_numerical(modelgridindex, decaypathindex, tstart); - - const int decaypathlength = get_decaypathlength(decaypathindex); + for (const auto &decaypath : decaypaths) { + const int decaypathlength = get_decaypathlength(decaypath); - // const double numerator = calculate_decaychain(1., meanlifetimes, decaypathlength + 1, tdiff, true); - // const double factor = numerator / calculate_decaychain(1., meanlifetimes, decaypathlength + 1, tdiff, false); - // printout(" Analytical expansion factor: %g\n", factor); - - const int z_top = decaypaths[decaypathindex].z[0]; - const int a_top = decaypaths[decaypathindex].a[0]; - const int nucindex_top = decaypaths[decaypathindex].nucindex[0]; + const int z_top = decaypath.z[0]; + const int a_top = decaypath.a[0]; + const int nucindex_top = decaypath.nucindex[0]; const double top_initabund = grid::get_modelinitradioabund(modelgridindex, nucindex_top) / nucmass(z_top, a_top); - const double chain_endecay = (decaypaths[decaypathindex].branchproduct * - calculate_decaychain(top_initabund, decaypaths[decaypathindex].lambdas, - decaypathlength + 1, tstart - grid::get_t_model(), true) * - get_decaypath_lastnucdecayenergy(decaypathindex)); + const double chain_endecay = (decaypath.branchproduct * + calculate_decaychain(top_initabund, decaypath.lambdas, decaypathlength + 1, + tstart - grid::get_t_model(), true) * + get_decaypath_lastnucdecayenergy(decaypath)); - // printout(" Analytical chain_endecay: %g\n", chain_endecay); tot_endecay += chain_endecay; } @@ -1044,7 +1036,7 @@ static auto get_decaypath_power_per_ejectamass(const int decaypathindex, const i const double t_afterinit = time - grid::get_t_model(); - int const decaypathlength = get_decaypathlength(decaypathindex); + const int decaypathlength = get_decaypathlength(decaypathindex); // contribution to the end nuclide abundance from the top of chain (could be a length-one chain Z,A_top = Z,A_end // so contribution would be from init abundance only) @@ -1085,7 +1077,7 @@ void setup_decaypath_energy_per_mass() { if (globals::rank_in_node == 0) { my_rank_cells += nonempty_npts_model - (my_rank_cells * globals::node_nprocs); } - MPI_Aint size = my_rank_cells * get_num_decaypaths() * sizeof(double); + auto size = static_cast(my_rank_cells * get_num_decaypaths() * sizeof(double)); int disp_unit = sizeof(double); assert_always(MPI_Win_allocate_shared(size, disp_unit, MPI_INFO_NULL, globals::mpi_comm_node, @@ -1102,7 +1094,7 @@ void setup_decaypath_energy_per_mass() { MPI_Barrier(MPI_COMM_WORLD); #endif - printout("Calculating for decaypath_energy_per_mass for all cells..."); + printout("Calculating decaypath_energy_per_mass for all cells..."); const int num_decaypaths = get_num_decaypaths(); for (int nonemptymgi = 0; nonemptymgi < nonempty_npts_model; nonemptymgi++) { if (nonemptymgi % globals::node_nprocs == globals::rank_in_node) { @@ -1142,9 +1134,6 @@ auto get_particle_injection_rate(const int modelgridindex, const double t, const double dep_sum = 0.; for (int nucindex = 0; nucindex < get_num_nuclides(); nucindex++) { const int z = get_nuc_z(nucindex); - if (z < 1) { - continue; - } const int a = get_nuc_a(nucindex); const double meanlife = get_meanlife(nucindex); if (meanlife < 0.) { @@ -1170,12 +1159,9 @@ auto get_qdot_modelcell(const int modelgridindex, const double t, const int deca double qdot = 0.; for (int nucindex = 0; nucindex < get_num_nuclides(); nucindex++) { const int z = get_nuc_z(nucindex); - if (z < 1) { - continue; - } const int a = get_nuc_a(nucindex); const double meanlife = get_meanlife(nucindex); - if (meanlife <= 0) { + if (meanlife < 0.) { continue; } const double q_decay = nucdecayenergyqval(nucindex, decaytype) * get_nuc_decaybranchprob(nucindex, decaytype); @@ -1203,12 +1189,10 @@ auto get_global_etot_t0_tinf() -> double { } void update_abundances(const int modelgridindex, const int timestep, const double t_current) -/// Updates the mass fractions of elements associated with the decay sequence +/// Updates the mass fractions of elements using the current abundances of nuclides /// Parameters: - modelgridindex: the grid cell for which to update the abundances /// - t_current: current time (here mid of current timestep) { - assert_always(!globals::homogeneous_abundances); // no longer supported - printout("update_abundances for cell %d timestep %d\n", modelgridindex, timestep); for (int element = get_nelements() - 1; element >= 0; element--) { @@ -1231,11 +1215,11 @@ void update_abundances(const int modelgridindex, const int timestep, const doubl } } else { // check if the nucleus decays off the network but into the selected element - for (int dectypeindex = 0; dectypeindex < DECAYTYPE_COUNT; dectypeindex++) { - const int daughter_z = decay_daughter_z(nuc_z, a, dectypeindex); - const int daughter_a = decay_daughter_a(nuc_z, a, dectypeindex); + for (const auto decaytype : all_decaytypes) { + const int daughter_z = decay_daughter_z(nuc_z, a, decaytype); + const int daughter_a = decay_daughter_a(nuc_z, a, decaytype); if (daughter_z == atomic_number && !nuc_exists(daughter_z, daughter_a) && - get_nuc_decaybranchprob(nuc_z, a, dectypeindex) > 0.) { + get_nuc_decaybranchprob(nuc_z, a, decaytype) > 0.) { if (!a_isotopes.contains(daughter_a)) { a_isotopes.insert(daughter_a); // nuclide decays into correct atomic number but outside of the radionuclide list @@ -1265,7 +1249,13 @@ void update_abundances(const int modelgridindex, const int timestep, const doubl grid::set_element_meanweight(modelgridindex, element, isomassfracsum / isomassfrac_on_nucmass_sum); } - // consider calling calculate_electron_densities() here + // total number of electrons in grid cell which are possible targets for compton scattering of gamma rays + double nnetot = 0.; + for (int element = 0; element < get_nelements(); element++) { + const double nnelement = grid::get_elem_numberdens(modelgridindex, element); + nnetot += nnelement * get_atomicnumber(element); + } + grid::set_nnetot(modelgridindex, nnetot); // double initnucfracsum = 0.; // double nucfracsum = 0.; @@ -1280,7 +1270,7 @@ void update_abundances(const int modelgridindex, const int timestep, const doubl // // printout(" init: %g now: %g\n", grid::get_modelinitradioabund(modelgridindex, z, a), // get_nuc_massfrac(modelgridindex, z, a, t_current)); // - // for (int dectypeindex = 0; dectypeindex < DECAYTYPE_COUNT; dectypeindex++) + // for (int dectypeindex = 0; dectypeindex < decaytypes::DECAYTYPE_COUNT; dectypeindex++) // { // if (!nuc_exists(decay_daughter_z(z, a, dectypeindex), decay_daughter_a(z, a, dectypeindex)) && // get_nuc_decaybranchprob(z, a, dectypeindex) > 0.) @@ -1323,12 +1313,12 @@ void fprint_nuc_abundances(FILE *estimators_file, const int modelgridindex, cons } } } else { // not the element that we want, but check if a decay produces it - for (int dectypeindex = 0; dectypeindex < DECAYTYPE_COUNT; dectypeindex++) { - const int daughter_z = decay_daughter_z(nuc_z, nuc_a, dectypeindex); - const int daughter_a = decay_daughter_a(nuc_z, nuc_a, dectypeindex); + for (const auto decaytype : all_decaytypes) { + const int daughter_z = decay_daughter_z(nuc_z, nuc_a, decaytype); + const int daughter_a = decay_daughter_a(nuc_z, nuc_a, decaytype); // if the nucleus exists, it will be picked up by the upper condition if (daughter_z == atomic_number && !nuc_exists(daughter_z, daughter_a) && - get_nuc_decaybranchprob(nucindex, dectypeindex) > 0.) { + get_nuc_decaybranchprob(nucindex, decaytype) > 0.) { if (!a_isotopes.contains(nuc_a)) { a_isotopes.insert(nuc_a); // nuclide decays into correct atomic number but outside of the radionuclide list. Daughter is assumed diff --git a/decay.h b/decay.h index e2c1b1096..9818656ba 100644 --- a/decay.h +++ b/decay.h @@ -3,9 +3,11 @@ // #include +#include #include #include +#include "constants.h" #include "packet.h" namespace decay { @@ -18,7 +20,11 @@ enum decaytypes { DECAYTYPE_COUNT = 5, }; -void init_nuclides(std::vector zlist, std::vector alist); +constexpr std::array all_decaytypes = { + decaytypes::DECAYTYPE_ALPHA, decaytypes::DECAYTYPE_ELECTRONCAPTURE, decaytypes::DECAYTYPE_BETAPLUS, + decaytypes::DECAYTYPE_BETAMINUS, decaytypes::DECAYTYPE_NONE}; + +void init_nuclides(const std::vector &zlist, const std::vector &alist); int get_nucstring_z(const std::string &strnuc); int get_nucstring_a(const std::string &strnuc); int get_num_nuclides(); @@ -30,7 +36,6 @@ bool nuc_exists(int z, int a); double nucdecayenergygamma(int nucindex); double nucdecayenergygamma(int z, int a); void set_nucdecayenergygamma(int nucindex, double value); -double nucmass(int z, int a); void update_abundances(int modelgridindex, int timestep, double t_current); double get_endecay_per_ejectamass_t0_to_time_withexpansion(int modelgridindex, double tstart); double get_modelcell_simtime_endecay_per_mass(int mgi); @@ -42,6 +47,8 @@ double get_global_etot_t0_tinf(); void fprint_nuc_abundances(FILE *estimators_file, int modelgridindex, double t_current, int element); void setup_radioactive_pellet(double e0, int mgi, struct packet *pkt_ptr); void cleanup(); + +auto constexpr nucmass(int z, int a) -> double { return a * MH; } } // namespace decay #endif // DECAY_H diff --git a/exspec.cc b/exspec.cc index 7254c3f6a..2f9727f67 100644 --- a/exspec.cc +++ b/exspec.cc @@ -1,15 +1,3 @@ -/* 2007-10-30 -- MK - Non-grey treatment of UVOIR opacity as opacity_case 4 added. - Still not fully commented. - Comments are marked by /// Deactivated code by // */ -/* 2007-01-17 -- MK - Several minor modifications (some marked in the code with //MK), these include - - global printout() routine (located in sn3d.c) - - opacity_cases 2 and 3 added (changes in grid_init.c and update_grid.c, - original opacity stuff was moved there from input.c) */ -/* This is a code copied from Lucy 2004 paper on t-dependent supernova - explosions. */ - #include "exspec.h" #include @@ -30,48 +18,146 @@ FILE *output_file = nullptr; int tid = 0; bool use_cellhist = false; -bool neutral_flag = false; -gsl_rng *rng = nullptr; -std::mt19937_64 *stdrng = nullptr; +std::mt19937 stdrng(std::random_device{}()); gsl_integration_workspace *gslworkspace = nullptr; -auto main(int argc, char *argv[]) -> int { - const time_t sys_time_start = time(nullptr); +static void do_angle_bin(const int a, packet *pkts, bool load_allrank_packets, struct spec &rpkt_spectra, + struct spec &stokes_i, struct spec &stokes_q, struct spec &stokes_u, + struct spec &gamma_spectra) { + std::vector rpkt_light_curve_lum(globals::ntimesteps, 0.); + std::vector rpkt_light_curve_lumcmf(globals::ntimesteps, 0.); + std::vector gamma_light_curve_lum(globals::ntimesteps, 0.); + std::vector gamma_light_curve_lumcmf(globals::ntimesteps, 0.); + + /// Set up the spectrum grid and initialise the bins to zero. + init_spectra(rpkt_spectra, NU_MIN_R, NU_MAX_R, globals::do_emission_res); + + if constexpr (POL_ON) { + init_spectra(stokes_i, NU_MIN_R, NU_MAX_R, globals::do_emission_res); + init_spectra(stokes_q, NU_MIN_R, NU_MAX_R, globals::do_emission_res); + init_spectra(stokes_u, NU_MIN_R, NU_MAX_R, globals::do_emission_res); + } + + const double nu_min_gamma = 0.05 * MEV / H; + const double nu_max_gamma = 4. * MEV / H; + init_spectra(gamma_spectra, nu_min_gamma, nu_max_gamma, false); + + for (int p = 0; p < globals::nprocs_exspec; p++) { + struct packet *pkts_start = load_allrank_packets ? &pkts[p * globals::npkts] : pkts; + + if (a == -1 || !load_allrank_packets) { + char pktfilename[MAXFILENAMELENGTH]; + snprintf(pktfilename, MAXFILENAMELENGTH, "packets%.2d_%.4d.out", 0, p); + printout("reading %s (file %d of %d)\n", pktfilename, p + 1, globals::nprocs_exspec); + + if (access(pktfilename, F_OK) == 0) { + read_packets(pktfilename, pkts_start); + } else { + printout(" WARNING %s does not exist - trying temp packets file at beginning of timestep %d...\n", + pktfilename, globals::timestep_initial); + read_temp_packetsfile(globals::timestep_initial, p, pkts_start); + } + } #ifdef MPI_ON - MPI_Init(&argc, &argv); - MPI_Comm_rank(MPI_COMM_WORLD, &globals::rank_global); - MPI_Comm_size(MPI_COMM_WORLD, &globals::nprocs); - - MPI_Comm_split_type(MPI_COMM_WORLD, MPI_COMM_TYPE_SHARED, globals::rank_global, MPI_INFO_NULL, - &globals::mpi_comm_node); - // get the local rank within this node - MPI_Comm_rank(globals::mpi_comm_node, &globals::rank_in_node); - // get the number of ranks on the node - MPI_Comm_size(globals::mpi_comm_node, &globals::node_nprocs); - MPI_Barrier(MPI_COMM_WORLD); + MPI_Barrier(MPI_COMM_WORLD); +#endif - // make an inter-node communicator (using local rank as the key for group membership) - MPI_Comm_split(MPI_COMM_WORLD, globals::rank_in_node, globals::rank_global, &globals::mpi_comm_internode); + if (p % globals::nprocs != globals::rank_global) { + printout("skipping packets file %d %d\n", p + 1, globals::nprocs); + continue; + } - // take the node id from the local rank 0 (node master) and broadcast it - if (globals::rank_in_node == 0) { - MPI_Comm_rank(globals::mpi_comm_internode, &globals::node_id); - MPI_Comm_size(globals::mpi_comm_internode, &globals::node_count); + int nesc_tot = 0; + int nesc_gamma = 0; + int nesc_rpkt = 0; + for (int ii = 0; ii < globals::npkts; ii++) { + // printout("packet %d escape_type %d type %d", ii, pkts[ii].escape_type, pkts[ii].type); + if (pkts_start[ii].type == TYPE_ESCAPE) { + nesc_tot++; + if (pkts_start[ii].escape_type == TYPE_RPKT) { + nesc_rpkt++; + add_to_lc_res(&pkts_start[ii], a, rpkt_light_curve_lum, rpkt_light_curve_lumcmf); + add_to_spec_res(&pkts_start[ii], a, rpkt_spectra, POL_ON ? &stokes_i : nullptr, POL_ON ? &stokes_q : nullptr, + POL_ON ? &stokes_u : nullptr); + } else if (pkts_start[ii].escape_type == TYPE_GAMMA) { + nesc_gamma++; + if (a == -1) { + add_to_lc_res(&pkts_start[ii], a, gamma_light_curve_lum, gamma_light_curve_lumcmf); + add_to_spec_res(&pkts_start[ii], a, gamma_spectra, nullptr, nullptr, nullptr); + } + } + } + } + if (a == -1 || !load_allrank_packets) { + printout(" %d of %d packets escaped (%d gamma-pkts and %d r-pkts)\n", nesc_tot, globals::npkts, nesc_gamma, + nesc_rpkt); + } } - MPI_Bcast(&globals::node_id, 1, MPI_INT, 0, globals::mpi_comm_node); - MPI_Bcast(&globals::node_count, 1, MPI_INT, 0, globals::mpi_comm_node); - MPI_Barrier(MPI_COMM_WORLD); -#else - globals::rank_global = 0; - globals::nprocs = 1; - globals::rank_in_node = 0; - globals::node_nprocs = 1; - globals::node_id = 0; - globals::node_count = 0; + if (a == -1) { + // angle-averaged spectra and light curves + write_light_curve("light_curve.out", -1, rpkt_light_curve_lum, rpkt_light_curve_lumcmf, globals::ntimesteps); + write_light_curve("gamma_light_curve.out", -1, gamma_light_curve_lum, gamma_light_curve_lumcmf, + globals::ntimesteps); + + write_spectrum("spec.out", "emission.out", "emissiontrue.out", "absorption.out", rpkt_spectra, globals::ntimesteps); + + if constexpr (POL_ON) { + write_specpol("specpol.out", "emissionpol.out", "absorptionpol.out", &stokes_i, &stokes_q, &stokes_u); + } + + write_spectrum("gamma_spec.out", "", "", "", gamma_spectra, globals::ntimesteps); + + printout("finished angle-averaged stuff\n"); + } else { + // direction bin a + // line-of-sight dependent spectra and light curves + + char lc_filename[MAXFILENAMELENGTH] = ""; + snprintf(lc_filename, MAXFILENAMELENGTH, "light_curve_res_%.2d.out", a); + + char spec_filename[MAXFILENAMELENGTH] = ""; + snprintf(spec_filename, MAXFILENAMELENGTH, "spec_res_%.2d.out", a); + + char emission_filename[MAXFILENAMELENGTH] = ""; + snprintf(emission_filename, MAXFILENAMELENGTH, "emission_res_%.2d.out", a); + + char trueemission_filename[MAXFILENAMELENGTH] = ""; + snprintf(trueemission_filename, MAXFILENAMELENGTH, "emissiontrue_res_%.2d.out", a); + + char absorption_filename[MAXFILENAMELENGTH] = ""; + snprintf(absorption_filename, MAXFILENAMELENGTH, "absorption_res_%.2d.out", a); + + write_light_curve(lc_filename, a, rpkt_light_curve_lum, rpkt_light_curve_lumcmf, globals::ntimesteps); + write_spectrum(spec_filename, emission_filename, trueemission_filename, absorption_filename, rpkt_spectra, + globals::ntimesteps); + + if constexpr (POL_ON) { + char specpol_filename[MAXFILENAMELENGTH] = ""; + snprintf(specpol_filename, MAXFILENAMELENGTH, "specpol_res_%.2d.out", a); + + char emissionpol_filename[MAXFILENAMELENGTH] = ""; + snprintf(emissionpol_filename, MAXFILENAMELENGTH, "emissionpol_res_%.2d.out", a); + + char absorptionpol_filename[MAXFILENAMELENGTH] = ""; + snprintf(absorptionpol_filename, MAXFILENAMELENGTH, "absorptionpol_res_%.2d.out", a); + + write_specpol(specpol_filename, emissionpol_filename, absorptionpol_filename, &stokes_i, &stokes_q, &stokes_u); + } + + printout("Did %d of %d angle bins.\n", a + 1, MABINS); + } +} + +auto main(int argc, char *argv[]) -> int { + const time_t sys_time_start = time(nullptr); + +#ifdef MPI_ON + MPI_Init(&argc, &argv); #endif - char filename[MAXFILENAMELENGTH]; + + globals::setup_mpi_vars(); globals::startofline = std::make_unique(get_max_threads()); if (globals::rank_global == 0) { @@ -83,10 +169,13 @@ auto main(int argc, char *argv[]) -> int { MPI_Barrier(MPI_COMM_WORLD); #endif + char filename[MAXFILENAMELENGTH]; if (globals::rank_global == 0) { snprintf(filename, MAXFILENAMELENGTH, "exspec.txt"); output_file = fopen_required(filename, "w"); setvbuf(output_file, nullptr, _IOLBF, 1); + } else { + output_file = nullptr; } printout("git branch %s\n", GIT_BRANCH); @@ -123,187 +212,51 @@ auto main(int argc, char *argv[]) -> int { printout("time before input %ld\n", time(nullptr)); input(globals::rank_global); printout("time after input %ld\n", time(nullptr)); + // nprocs_exspec is the number of rank output files to process with expec // however, we might be running exspec with 1 or just a few ranks - globals::nprocs = globals::nprocs_exspec; - - constexpr double maxpktmem_mb = 16000; - bool load_allrank_packets = false; - if ((globals::nprocs_exspec * globals::npkts * sizeof(struct packet) / 1024. / 1024.) < maxpktmem_mb) { - printout( - "mem_usage: loading packets from all %d processes simultaneously (total %d packets, %.1f MB memory is within " - "limit of %.1f MB)\n", - globals::nprocs_exspec, globals::nprocs_exspec * globals::npkts, - globals::nprocs_exspec * globals::npkts * sizeof(struct packet) / 1024. / 1024., maxpktmem_mb); - load_allrank_packets = true; + auto *pkts = static_cast(malloc(globals::nprocs_exspec * globals::npkts * sizeof(struct packet))); + const bool load_allrank_packets = (pkts != nullptr); + if (load_allrank_packets) { + printout("mem_usage: loading %d packets from each %d processes simultaneously (total %d packets, %.1f MB memory)\n", + globals::npkts, globals::nprocs_exspec, globals::nprocs_exspec * globals::npkts, + globals::nprocs_exspec * globals::npkts * sizeof(struct packet) / 1024. / 1024.); } else { + printout("mem_usage: malloc failed to allocate memory for all packets\n"); printout( - "mem_usage: loading packets from each of %d processes sequentially (total %d packets, %.1f MB memory would be " - "above limit of %.1f MB)\n", - globals::nprocs_exspec, globals::nprocs_exspec * globals::npkts, - globals::nprocs_exspec * globals::npkts * sizeof(struct packet) / 1024. / 1024., maxpktmem_mb); - load_allrank_packets = false; + "mem_usage: loading %d packets from each of %d processes sequentially (total %d packets, %.1f MB memory)\n", + globals::npkts, globals::nprocs_exspec, globals::nprocs_exspec * globals::npkts, + globals::nprocs_exspec * globals::npkts * sizeof(struct packet) / 1024. / 1024.); + auto *pkts = static_cast(malloc(globals::npkts * sizeof(struct packet))); + assert_always(pkts != nullptr); } - const int npkts_loaded = load_allrank_packets ? globals::nprocs_exspec * globals::npkts : globals::npkts; - auto *pkts = static_cast(malloc(npkts_loaded * sizeof(struct packet))); - init_spectrum_trace(); // needed for TRACE_EMISSION_ABSORPTION_REGION_ON - auto rpkt_spectra = alloc_spectra(globals::do_emission_res); - - std::unique_ptr stokes_i = nullptr; - std::unique_ptr stokes_q = nullptr; - std::unique_ptr stokes_u = nullptr; + struct spec rpkt_spectra; - if constexpr (POL_ON) { - stokes_i = alloc_spectra(globals::do_emission_res); - stokes_q = alloc_spectra(globals::do_emission_res); - stokes_u = alloc_spectra(globals::do_emission_res); - } + struct spec stokes_i; + struct spec stokes_q; + struct spec stokes_u; - auto gamma_spectra = alloc_spectra(false); + struct spec gamma_spectra; - /// Initialise the grid. Call routine that sets up the initial positions - /// and sizes of the grid cells. - // grid_init(); time_init(); - const int amax = ((grid::get_model_type() == grid::RHO_1D_READ)) ? 0 : MABINS; + const int amax = ((grid::get_model_type() == GRID_SPHERICAL1D)) ? 0 : MABINS; // a is the escape direction angle bin for (int a = -1; a < amax; a++) { - /// Set up the light curve grid and initialise the bins to zero. - std::vector rpkt_light_curve_lum(globals::ntstep, 0.); - std::vector rpkt_light_curve_lumcmf(globals::ntstep, 0.); - std::vector gamma_light_curve_lum(globals::ntstep, 0.); - std::vector gamma_light_curve_lumcmf(globals::ntstep, 0.); - /// Set up the spectrum grid and initialise the bins to zero. - - init_spectra(*rpkt_spectra, NU_MIN_R, NU_MAX_R, globals::do_emission_res); - - if constexpr (POL_ON) { - init_spectra(*stokes_i, NU_MIN_R, NU_MAX_R, globals::do_emission_res); - init_spectra(*stokes_q, NU_MIN_R, NU_MAX_R, globals::do_emission_res); - init_spectra(*stokes_u, NU_MIN_R, NU_MAX_R, globals::do_emission_res); - } - - const double nu_min_gamma = 0.05 * MEV / H; - const double nu_max_gamma = 4. * MEV / H; - init_spectra(*gamma_spectra, nu_min_gamma, nu_max_gamma, false); - - for (int p = 0; p < globals::nprocs_exspec; p++) { - struct packet *pkts_start = load_allrank_packets ? &pkts[p * globals::npkts] : pkts; - - if (a == -1 || !load_allrank_packets) { - char pktfilename[MAXFILENAMELENGTH]; - snprintf(pktfilename, MAXFILENAMELENGTH, "packets%.2d_%.4d.out", 0, p); - printout("reading %s (file %d of %d)\n", pktfilename, p + 1, globals::nprocs_exspec); - - if (access(pktfilename, F_OK) == 0) { - read_packets(pktfilename, pkts_start); - } else { - printout(" WARNING %s does not exist - trying temp packets file at beginning of timestep %d...\n ", - pktfilename, globals::itstep); - read_temp_packetsfile(globals::itstep, p, pkts_start); - } - } - - int nesc_tot = 0; - int nesc_gamma = 0; - int nesc_rpkt = 0; - for (int ii = 0; ii < globals::npkts; ii++) { - // printout("packet %d escape_type %d type %d", ii, pkts[ii].escape_type, pkts[ii].type); - if (pkts_start[ii].type == TYPE_ESCAPE) { - nesc_tot++; - if (pkts_start[ii].escape_type == TYPE_RPKT) { - nesc_rpkt++; - add_to_lc_res(&pkts_start[ii], a, rpkt_light_curve_lum.data(), rpkt_light_curve_lumcmf.data()); - add_to_spec_res(&pkts_start[ii], a, *rpkt_spectra, stokes_i.get(), stokes_q.get(), stokes_u.get()); - } else if (pkts_start[ii].escape_type == TYPE_GAMMA) { - nesc_gamma++; - if (a == -1) { - add_to_lc_res(&pkts_start[ii], a, gamma_light_curve_lum.data(), gamma_light_curve_lumcmf.data()); - add_to_spec_res(&pkts_start[ii], a, *gamma_spectra, nullptr, nullptr, nullptr); - } - } - } - } - if (a == -1 || !load_allrank_packets) { - printout(" %d of %d packets escaped (%d gamma-pkts and %d r-pkts)\n", nesc_tot, globals::npkts, nesc_gamma, - nesc_rpkt); - } - } - - if (a == -1) { - // angle-averaged spectra and light curves - write_light_curve("light_curve.out", -1, rpkt_light_curve_lum.data(), rpkt_light_curve_lumcmf.data(), - globals::ntstep); - write_light_curve("gamma_light_curve.out", -1, gamma_light_curve_lum.data(), gamma_light_curve_lumcmf.data(), - globals::ntstep); - - write_spectrum("spec.out", "emission.out", "emissiontrue.out", "absorption.out", *rpkt_spectra, globals::ntstep); - - if constexpr (POL_ON) { - write_specpol("specpol.out", "emissionpol.out", "absorptionpol.out", stokes_i.get(), stokes_q.get(), - stokes_u.get()); - } - - write_spectrum("gamma_spec.out", nullptr, nullptr, nullptr, *gamma_spectra, globals::ntstep); - - printout("finished angle-averaged stuff\n"); - } else { - // direction bin a - // line-of-sight dependent spectra and light curves - - char lc_filename[MAXFILENAMELENGTH] = ""; - snprintf(lc_filename, MAXFILENAMELENGTH, "light_curve_res_%.2d.out", a); - - char spec_filename[MAXFILENAMELENGTH] = ""; - snprintf(spec_filename, MAXFILENAMELENGTH, "spec_res_%.2d.out", a); - - char emission_filename[MAXFILENAMELENGTH] = ""; - snprintf(emission_filename, MAXFILENAMELENGTH, "emission_res_%.2d.out", a); - - char trueemission_filename[MAXFILENAMELENGTH] = ""; - snprintf(trueemission_filename, MAXFILENAMELENGTH, "emissiontrue_res_%.2d.out", a); - - char absorption_filename[MAXFILENAMELENGTH] = ""; - snprintf(absorption_filename, MAXFILENAMELENGTH, "absorption_res_%.2d.out", a); - - write_light_curve(lc_filename, a, rpkt_light_curve_lum.data(), rpkt_light_curve_lumcmf.data(), globals::ntstep); - write_spectrum(spec_filename, emission_filename, trueemission_filename, absorption_filename, *rpkt_spectra, - globals::ntstep); - - if constexpr (POL_ON) { - char specpol_filename[MAXFILENAMELENGTH] = ""; - snprintf(specpol_filename, MAXFILENAMELENGTH, "specpol_res_%.2d.out", a); - - char emissionpol_filename[MAXFILENAMELENGTH] = ""; - snprintf(emissionpol_filename, MAXFILENAMELENGTH, "emissionpol_res_%.2d.out", a); - - char absorptionpol_filename[MAXFILENAMELENGTH] = ""; - snprintf(absorptionpol_filename, MAXFILENAMELENGTH, "absorptionpol_res_%.2d.out", a); - - write_specpol(specpol_filename, emissionpol_filename, absorptionpol_filename, stokes_i.get(), stokes_q.get(), - stokes_u.get()); - } - - printout("Did %d of %d angle bins.\n", a + 1, MABINS); - } + do_angle_bin(a, pkts, load_allrank_packets, rpkt_spectra, stokes_i, stokes_q, stokes_u, gamma_spectra); } - rpkt_spectra.reset(); - stokes_i.reset(); - stokes_q.reset(); - stokes_u.reset(); - gamma_spectra.reset(); - free(pkts); decay::cleanup(); - printout("exspec finished at %ld (tstart + %ld seconds)\n", time(nullptr), time(nullptr) - sys_time_start); - fclose(output_file); + + if (output_file != nullptr) { + fclose(output_file); + } #ifdef MPI_ON MPI_Finalize(); diff --git a/gammapkt.cc b/gammapkt.cc index e8b9dd377..545fb711a 100644 --- a/gammapkt.cc +++ b/gammapkt.cc @@ -8,7 +8,6 @@ #include #include -#include "boundary.h" #include "decay.h" #include "grid.h" #include "nonthermal.h" @@ -201,13 +200,13 @@ void init_gamma_linelist() { } void normalise_grey(int nts) { - const double dt = globals::time_step[nts].width; - globals::time_step[nts].gamma_dep_pathint = 0.; + const double dt = globals::timesteps[nts].width; + globals::timesteps[nts].gamma_dep_pathint = 0.; for (int mgi = 0; mgi < grid::get_npts_model(); mgi++) { if (grid::get_numassociatedcells(mgi) > 0) { - const double dV = grid::get_modelcell_assocvolume_tmin(mgi) * pow(globals::time_step[nts].mid / globals::tmin, 3); + const double dV = grid::get_modelcell_assocvolume_tmin(mgi) * pow(globals::timesteps[nts].mid / globals::tmin, 3); - globals::time_step[nts].gamma_dep_pathint += globals::rpkt_emiss[mgi] / globals::nprocs; + globals::timesteps[nts].gamma_dep_pathint += globals::rpkt_emiss[mgi] / globals::nprocs; globals::rpkt_emiss[mgi] = globals::rpkt_emiss[mgi] * ONEOVER4PI / dV / dt / globals::nprocs; @@ -221,7 +220,7 @@ static void choose_gamma_ray(struct packet *pkt_ptr) { // Routine to choose which gamma ray line it'll be. const int nucindex = pkt_ptr->pellet_nucindex; - double const E_gamma = decay::nucdecayenergygamma(nucindex); // Average energy per gamma line of a decay + const double E_gamma = decay::nucdecayenergygamma(nucindex); // Average energy per gamma line of a decay const double zrand = rng_uniform(); int nselected = -1; @@ -283,20 +282,18 @@ void pellet_gamma_decay(struct packet *pkt_ptr) { // that it's now a gamma ray. pkt_ptr->prop_time = pkt_ptr->tdecay; - const double dopplerfactor = doppler_packet_nucmf_on_nurf(pkt_ptr); + const double dopplerfactor = doppler_packet_nucmf_on_nurf(pkt_ptr->pos, pkt_ptr->dir, pkt_ptr->prop_time); pkt_ptr->nu_rf = pkt_ptr->nu_cmf / dopplerfactor; pkt_ptr->e_rf = pkt_ptr->e_cmf / dopplerfactor; pkt_ptr->type = TYPE_GAMMA; - pkt_ptr->last_cross = NONE; + pkt_ptr->last_cross = BOUNDARY_NONE; // initialise polarisation information pkt_ptr->stokes[0] = 1.0; pkt_ptr->stokes[1] = pkt_ptr->stokes[2] = 0.0; - double dummy_dir[3]; + std::array dummy_dir = {0., 0., 1.}; - dummy_dir[0] = dummy_dir[1] = 0.0; - dummy_dir[2] = 1.0; cross_prod(pkt_ptr->dir, dummy_dir, pkt_ptr->pol_dir); if ((dot(pkt_ptr->pol_dir, pkt_ptr->pol_dir)) < 1.e-8) { dummy_dir[0] = dummy_dir[2] = 0.0; @@ -322,35 +319,34 @@ constexpr auto sigma_compton_partial(const double x, const double f) -> double return (3 * SIGMA_T * (term1 + term2 + term3) / (8 * x)); } -static auto sig_comp(const struct packet *pkt_ptr) -> double { +static auto get_chi_compton_rf(const struct packet *pkt_ptr) -> double { + // calculate the absorption coefficient [cm^-1] for Compton scattering in the observer reference frame // Start by working out the compton x-section in the co-moving frame. - double const xx = H * pkt_ptr->nu_cmf / ME / CLIGHT / CLIGHT; + const double xx = H * pkt_ptr->nu_cmf / ME / CLIGHT / CLIGHT; // Use this to decide whether the Thompson limit is acceptable. - double sigma_cmf = NAN; + double sigma_cmf; if (xx < THOMSON_LIMIT) { sigma_cmf = SIGMA_T; } else { - double const fmax = (1 + (2 * xx)); + const double fmax = (1 + (2 * xx)); sigma_cmf = sigma_compton_partial(xx, fmax); } // Now need to multiply by the electron number density. - const int cellindex = pkt_ptr->where; - sigma_cmf *= grid::get_nnetot(grid::get_cell_modelgridindex(cellindex)); - - // Now need to convert between frames. + const double chi_cmf = sigma_cmf * grid::get_nnetot(grid::get_cell_modelgridindex(pkt_ptr->where)); - const double sigma_rf = sigma_cmf * doppler_packet_nucmf_on_nurf(pkt_ptr); + // convert between frames + const double chi_rf = chi_cmf * doppler_packet_nucmf_on_nurf(pkt_ptr->pos, pkt_ptr->dir, pkt_ptr->prop_time); - assert_testmodeonly(std::isfinite(sigma_rf)); + assert_testmodeonly(std::isfinite(chi_rf)); - return sigma_rf; + return chi_rf; } -static auto choose_f(double xx, double zrand) -> double +static auto choose_f(const double xx, const double zrand) -> double // To choose the value of f to integrate to - idea is we want // sigma_compton_partial(xx,f) = zrand. { @@ -472,7 +468,7 @@ static void compton_scatter(struct packet *pkt_ptr) const double cos_theta = (xx < THOMSON_LIMIT) ? thomson_angle() : 1. - ((f - 1) / xx); - double new_dir[3]; + double new_dir[3] = {NAN, NAN, NAN}; scatter_dir(cmf_dir, cos_theta, new_dir); const double test = dot(new_dir, new_dir); @@ -504,11 +500,11 @@ static void compton_scatter(struct packet *pkt_ptr) // It now has a rest frame direction and a co-moving frequency. // Just need to set the rest frame energy. - const double dopplerfactor = doppler_packet_nucmf_on_nurf(pkt_ptr); + const double dopplerfactor = doppler_packet_nucmf_on_nurf(pkt_ptr->pos, pkt_ptr->dir, pkt_ptr->prop_time); pkt_ptr->nu_rf = pkt_ptr->nu_cmf / dopplerfactor; pkt_ptr->e_rf = pkt_ptr->e_cmf / dopplerfactor; - pkt_ptr->last_cross = NONE; // allow it to re-cross a boundary + pkt_ptr->last_cross = BOUNDARY_NONE; // allow it to re-cross a boundary } else { // It's converted to an e-minus packet. pkt_ptr->type = TYPE_NTLEPTON; @@ -517,126 +513,124 @@ static void compton_scatter(struct packet *pkt_ptr) } } -static auto sig_photo_electric(const struct packet *pkt_ptr) -> double { - // photo electric effect scattering +static auto get_chi_photo_electric_rf(const struct packet *pkt_ptr) -> double { + // calculate the absorption coefficient [cm^-1] for photo electric effect scattering in the observer reference frame - double sigma_cmf = NAN; + double chi_cmf = NAN; // Start by working out the x-section in the co-moving frame. const int mgi = grid::get_cell_modelgridindex(pkt_ptr->where); const double rho = grid::get_rho(mgi); - if (globals::gamma_grey < 0) { - // double sigma_cmf_cno = 0.0448e-24 * pow(pkt_ptr->nu_cmf / 2.41326e19, -3.2); + if (globals::gamma_kappagrey < 0) { + // Cross sections from Equation 2 of Ambwani & Sutherland (1988), attributed to Veigele (1973) - double sigma_cmf_si = 1.16e-24 * pow(pkt_ptr->nu_cmf / 2.41326e19, -3.13); + // 2.41326e19 Hz = 100 keV / H + const double hnu_over_100kev = pkt_ptr->nu_cmf / 2.41326e+19; - double sigma_cmf_fe = 25.7e-24 * pow(pkt_ptr->nu_cmf / 2.41326e19, -3.0); + // double sigma_cmf_cno = 0.0448e-24 * pow(hnu_over_100kev, -3.2); - // 2.41326e19 = 100keV in frequency. + const double sigma_cmf_si = 1.16e-24 * pow(hnu_over_100kev, -3.13); - // Now need to multiply by the particle number density. + const double sigma_cmf_fe = 25.7e-24 * pow(hnu_over_100kev, -3.0); - // sigma_cmf_cno *= rho * (1. - f_fe) / MH / 14; - // Assumes Z = 7. So mass = 14. + // Now need to multiply by the particle number density. - sigma_cmf_si *= rho / MH / 28; + const double chi_cmf_si = sigma_cmf_si * (rho / MH / 28); // Assumes Z = 14. So mass = 28. - sigma_cmf_fe *= rho / MH / 56; + const double chi_cmf_fe = sigma_cmf_fe * (rho / MH / 56); // Assumes Z = 28. So mass = 56. const double f_fe = grid::get_ffegrp(mgi); - sigma_cmf = (sigma_cmf_fe * f_fe) + (sigma_cmf_si * (1. - f_fe)); + chi_cmf = (chi_cmf_fe * f_fe) + (chi_cmf_si * (1. - f_fe)); } else { - sigma_cmf = globals::gamma_grey * rho; + chi_cmf = globals::gamma_kappagrey * rho; } - // Now need to convert between frames. + // Now convert between frames. - const double sigma_rf = sigma_cmf * doppler_packet_nucmf_on_nurf(pkt_ptr); - return sigma_rf; + const double chi_rf = chi_cmf * doppler_packet_nucmf_on_nurf(pkt_ptr->pos, pkt_ptr->dir, pkt_ptr->prop_time); + return chi_rf; } -static auto sig_pair_prod(const struct packet *pkt_ptr) -> double { - // Cross section for pair production. +static auto sigma_pair_prod_rf(const struct packet *pkt_ptr) -> double { + // calculate the absorption coefficient [cm^-1] for pair production in the observer reference frame - double sigma_cmf = NAN; + const int mgi = grid::get_cell_modelgridindex(pkt_ptr->where); + const double rho = grid::get_rho(mgi); - // Start by working out the x-section in the co-moving frame. + if (globals::gamma_kappagrey >= 0.) { + return 0.; + } - const int cellindex = pkt_ptr->where; - const int mgi = grid::get_cell_modelgridindex(cellindex); - const double rho = grid::get_rho(mgi); + // 2.46636e+20 Hz = 1022 keV / H + if (pkt_ptr->nu_cmf <= 2.46636e+20) { + return 0.; + } - if (globals::gamma_grey < 0) { - // 2.46636e+20 = 1022 keV in frequency - // 3.61990e+20 = 1500 keV in frequency + // double sigma_cmf_cno; + double sigma_cmf_si = NAN; + double sigma_cmf_fe = NAN; + const double f_fe = grid::get_ffegrp(mgi); - if (pkt_ptr->nu_cmf > 2.46636e+20) { - // double sigma_cmf_cno; - double sigma_cmf_si = NAN; - double sigma_cmf_fe = NAN; - const double f_fe = grid::get_ffegrp(mgi); - if (pkt_ptr->nu_cmf > 3.61990e+20) { - // sigma_cmf_cno = (0.0481 + (0.301 * ((pkt_ptr->nu_cmf/2.41326e+20) - 1.5))) * 49.e-27; + // Cross sections from Equation 2 of Ambwani & Sutherland (1988), attributed to Hubbell (1969) - sigma_cmf_si = (0.0481 + (0.301 * ((pkt_ptr->nu_cmf / 2.41326e+20) - 1.5))) * 196.e-27; + // 3.61990e+20 = 1500 keV in frequency / H + const double hnu_over_mev = pkt_ptr->nu_cmf / 2.41326e+20; + if (pkt_ptr->nu_cmf > 3.61990e+20) { + // sigma_cmf_cno = (0.0481 + (0.301 * (hnu_over_mev - 1.5))) * 49.e-27; - sigma_cmf_fe = (0.0481 + (0.301 * ((pkt_ptr->nu_cmf / 2.41326e+20) - 1.5))) * 784.e-27; - } else { - // sigma_cmf_cno = 1.0063 * ((pkt_ptr->nu_cmf/2.41326e+20) - 1.022) * 49.e-27; + sigma_cmf_si = (0.0481 + (0.301 * (hnu_over_mev - 1.5))) * 196.e-27; - sigma_cmf_si = 1.0063 * ((pkt_ptr->nu_cmf / 2.41326e+20) - 1.022) * 196.e-27; + sigma_cmf_fe = (0.0481 + (0.301 * (hnu_over_mev - 1.5))) * 784.e-27; + } else { + // sigma_cmf_cno = 1.0063 * (hnu_over_mev - 1.022) * 49.e-27; - sigma_cmf_fe = 1.0063 * ((pkt_ptr->nu_cmf / 2.41326e+20) - 1.022) * 784.e-27; - } + sigma_cmf_si = 1.0063 * (hnu_over_mev - 1.022) * 196.e-27; - // Now need to multiply by the particle number density. + sigma_cmf_fe = 1.0063 * (hnu_over_mev - 1.022) * 784.e-27; + } - // sigma_cmf_cno *= rho * (1. - f_fe) / MH / 14; - // Assumes Z = 7. So mass = 14. + // multiply by the particle number density. - sigma_cmf_si *= rho / MH / 28; - // Assumes Z = 14. So mass = 28. + // sigma_cmf_cno *= rho * (1. - f_fe) / MH / 14; + // Assumes Z = 7. So mass = 14. - sigma_cmf_fe *= rho / MH / 56; - // Assumes Z = 28. So mass = 56. + const double chi_cmf_si = sigma_cmf_si * (rho / MH / 28); + // Assumes Z = 14. So mass = 28. - sigma_cmf = (sigma_cmf_fe * f_fe) + (sigma_cmf_si * (1. - f_fe)); - } else { - sigma_cmf = 0.0; - } - } else { - sigma_cmf = 0.0; - } + const double chi_cmf_fe = sigma_cmf_fe * (rho / MH / 56); + // Assumes Z = 28. So mass = 56. + + const double chi_cmf = (chi_cmf_fe * f_fe) + (chi_cmf_si * (1. - f_fe)); // Now need to convert between frames. - double sigma_rf = sigma_cmf * doppler_packet_nucmf_on_nurf(pkt_ptr); + double chi_rf = chi_cmf * doppler_packet_nucmf_on_nurf(pkt_ptr->pos, pkt_ptr->dir, pkt_ptr->prop_time); - if (sigma_rf < 0) { - printout("Negative pair production sigma. Setting to zero. Abort? %g\n", sigma_rf); - sigma_rf = 0.0; + if (chi_rf < 0) { + printout("Negative pair production sigma. Setting to zero. Abort? %g\n", chi_rf); + chi_rf = 0.0; } - return sigma_rf; + return chi_rf; } constexpr auto meanf_sigma(const double x) -> double // Routine to compute the mean energy converted to non-thermal electrons times // the Klein-Nishina cross section. { - double const f = 1 + (2 * x); + const double f = 1 + (2 * x); - double const term0 = 2 / x; - double const term1 = (1 - (2 / x) - (3 / (x * x))) * log(f); - double const term2 = ((4 / x) + (3 / (x * x)) - 1) * 2 * x / f; - double const term3 = (1 - (2 / x) - (1 / (x * x))) * 2 * x * (1 + x) / f / f; - double const term4 = -2. * x * ((4 * x * x) + (6 * x) + 3) / 3 / f / f / f; + const double term0 = 2 / x; + const double term1 = (1 - (2 / x) - (3 / (x * x))) * log(f); + const double term2 = ((4 / x) + (3 / (x * x)) - 1) * 2 * x / f; + const double term3 = (1 - (2 / x) - (1 / (x * x))) * 2 * x * (1 + x) / f / f; + const double term4 = -2. * x * ((4 * x * x) + (6 * x) + 3) / 3 / f / f / f; - double const tot = 3 * SIGMA_T * (term0 + term1 + term2 + term3 + term4) / (8 * x); + const double tot = 3 * SIGMA_T * (term0 + term1 + term2 + term3 + term4) / (8 * x); return tot; } @@ -655,33 +649,30 @@ static void rlc_emiss_gamma(const struct packet *pkt_ptr, const double dist) { // Called with a packet that is about to travel a // distance dist in the lab frame. - const int cellindex = pkt_ptr->where; - const int mgi = grid::get_cell_modelgridindex(cellindex); - - if (dist > 0) { - double vel_vec[3]; - get_velocity(pkt_ptr->pos, vel_vec, pkt_ptr->prop_time); - - double const doppler_sq = doppler_squared_nucmf_on_nurf(pkt_ptr->dir, vel_vec); - - const double xx = H * pkt_ptr->nu_cmf / ME / CLIGHT / CLIGHT; - double heating_cont = ((meanf_sigma(xx) * grid::get_nnetot(mgi)) + sig_photo_electric(pkt_ptr) + - (sig_pair_prod(pkt_ptr) * (1. - (2.46636e+20 / pkt_ptr->nu_cmf)))); - heating_cont = heating_cont * pkt_ptr->e_rf * dist * doppler_sq; + if (!(dist > 0)) { + return; + } - // The terms in the above are for Compton, photoelectric and pair production. The pair production one - // assumes that a fraction (1. - (1.022 MeV / nu)) of the gamma's energy is thermalised. - // The remaining 1.022 MeV is made into gamma rays + const double doppler_sq = doppler_squared_nucmf_on_nurf(pkt_ptr->pos, pkt_ptr->dir, pkt_ptr->prop_time); - // For normalisation this needs to be - // 1) divided by volume - // 2) divided by the length of the time step - // 3) divided by 4 pi sr - // This will all be done later - assert_testmodeonly(heating_cont >= 0.); - assert_testmodeonly(isfinite(heating_cont)); - safeadd(globals::rpkt_emiss[mgi], heating_cont); - } + const int mgi = grid::get_cell_modelgridindex(pkt_ptr->where); + const double xx = H * pkt_ptr->nu_cmf / ME / CLIGHT / CLIGHT; + double heating_cont = ((meanf_sigma(xx) * grid::get_nnetot(mgi)) + get_chi_photo_electric_rf(pkt_ptr) + + (sigma_pair_prod_rf(pkt_ptr) * (1. - (2.46636e+20 / pkt_ptr->nu_cmf)))); + heating_cont = heating_cont * pkt_ptr->e_rf * dist * doppler_sq; + + // The terms in the above are for Compton, photoelectric and pair production. The pair production one + // assumes that a fraction (1. - (1.022 MeV / nu)) of the gamma's energy is thermalised. + // The remaining 1.022 MeV is made into gamma rays + + // For normalisation this needs to be + // 1) divided by volume + // 2) divided by the length of the time step + // 3) divided by 4 pi sr + // This will all be done later + assert_testmodeonly(heating_cont >= 0.); + assert_testmodeonly(isfinite(heating_cont)); + safeadd(globals::rpkt_emiss[mgi], heating_cont); } void pair_prod(struct packet *pkt_ptr) { @@ -727,12 +718,12 @@ void pair_prod(struct packet *pkt_ptr) { angle_ab(dir_cmf, vel_vec, pkt_ptr->dir); - const double dopplerfactor = doppler_packet_nucmf_on_nurf(pkt_ptr); + const double dopplerfactor = doppler_packet_nucmf_on_nurf(pkt_ptr->pos, pkt_ptr->dir, pkt_ptr->prop_time); pkt_ptr->nu_rf = pkt_ptr->nu_cmf / dopplerfactor; pkt_ptr->e_rf = pkt_ptr->e_cmf / dopplerfactor; pkt_ptr->type = TYPE_GAMMA; - pkt_ptr->last_cross = NONE; + pkt_ptr->last_cross = BOUNDARY_NONE; } } @@ -752,11 +743,12 @@ void do_gamma(struct packet *pkt_ptr, double t2) // grid cell into which we pass. int snext = 0; - double sdist = boundary_cross(pkt_ptr, &snext); + double sdist = grid::boundary_distance(pkt_ptr->dir, pkt_ptr->pos, pkt_ptr->prop_time, pkt_ptr->where, &snext, + &pkt_ptr->last_cross); - const double maxsdist = (GRID_TYPE == GRID_SPHERICAL1D) - ? 2 * globals::rmax * (pkt_ptr->prop_time + sdist / CLIGHT_PROP) / globals::tmin - : globals::rmax * pkt_ptr->prop_time / globals::tmin; + const double maxsdist = (GRID_TYPE == GRID_CARTESIAN3D) + ? globals::rmax * pkt_ptr->prop_time / globals::tmin + : 2 * globals::rmax * (pkt_ptr->prop_time + sdist / CLIGHT_PROP) / globals::tmin; if (sdist > maxsdist) { printout("Unreasonably large sdist (gamma). Abort. %g %g %g\n", globals::rmax, pkt_ptr->prop_time / globals::tmin, sdist); @@ -783,22 +775,22 @@ void do_gamma(struct packet *pkt_ptr, double t2) // Compton scattering - need to determine the scattering co-efficient. // Routine returns the value in the rest frame. - double kap_compton = 0.0; - if (globals::gamma_grey < 0) { - kap_compton = sig_comp(pkt_ptr); + double chi_compton = 0.0; + if (globals::gamma_kappagrey < 0) { + chi_compton = get_chi_compton_rf(pkt_ptr); } - const double kap_photo_electric = sig_photo_electric(pkt_ptr); - const double kap_pair_prod = sig_pair_prod(pkt_ptr); - const double kap_tot = kap_compton + kap_photo_electric + kap_pair_prod; + const double chi_photo_electric = get_chi_photo_electric_rf(pkt_ptr); + const double chi_pair_prod = sigma_pair_prod_rf(pkt_ptr); + const double chi_tot = chi_compton + chi_photo_electric + chi_pair_prod; - assert_testmodeonly(std::isfinite(kap_compton)); - assert_testmodeonly(std::isfinite(kap_photo_electric)); - assert_testmodeonly(std::isfinite(kap_pair_prod)); + assert_testmodeonly(std::isfinite(chi_compton)); + assert_testmodeonly(std::isfinite(chi_photo_electric)); + assert_testmodeonly(std::isfinite(chi_pair_prod)); // So distance before physical event is... - double const edist = (tau_next - tau_current) / kap_tot; + const double edist = (tau_next - tau_current) / chi_tot; if (edist < 0) { printout("Negative distance (edist). Abort. \n"); @@ -807,7 +799,7 @@ void do_gamma(struct packet *pkt_ptr, double t2) // Find how far it can travel during the time inverval. - double const tdist = (t2 - pkt_ptr->prop_time) * CLIGHT_PROP; + const double tdist = (t2 - pkt_ptr->prop_time) * CLIGHT_PROP; if (tdist < 0) { printout("Negative distance (tdist). Abort. \n"); @@ -821,7 +813,7 @@ void do_gamma(struct packet *pkt_ptr, double t2) move_pkt(pkt_ptr, sdist / 2.); // Move it into the new cell. - if (kap_tot > 0) { + if (chi_tot > 0) { rlc_emiss_gamma(pkt_ptr, sdist); } @@ -829,14 +821,14 @@ void do_gamma(struct packet *pkt_ptr, double t2) move_pkt(pkt_ptr, sdist / 2.); if (snext != pkt_ptr->where) { - change_cell(pkt_ptr, snext); + grid::change_cell(pkt_ptr, snext); } } else if ((tdist < sdist) && (tdist < edist)) { // Doesn't reach boundary. pkt_ptr->prop_time += tdist / 2. / CLIGHT_PROP; move_pkt(pkt_ptr, tdist / 2.); - if (kap_tot > 0) { + if (chi_tot > 0) { rlc_emiss_gamma(pkt_ptr, tdist); } pkt_ptr->prop_time = t2; @@ -844,7 +836,7 @@ void do_gamma(struct packet *pkt_ptr, double t2) } else if ((edist < sdist) && (edist < tdist)) { pkt_ptr->prop_time += edist / 2. / CLIGHT_PROP; move_pkt(pkt_ptr, edist / 2.); - if (kap_tot > 0) { + if (chi_tot > 0) { rlc_emiss_gamma(pkt_ptr, edist); } pkt_ptr->prop_time += edist / 2. / CLIGHT_PROP; @@ -852,24 +844,24 @@ void do_gamma(struct packet *pkt_ptr, double t2) // event occurs. Choose which event and call the appropriate subroutine. zrand = rng_uniform(); - if (kap_compton > (zrand * kap_tot)) { + if (chi_compton > (zrand * chi_tot)) { // Compton scattering. compton_scatter(pkt_ptr); - } else if ((kap_compton + kap_photo_electric) > (zrand * kap_tot)) { + } else if ((chi_compton + chi_photo_electric) > (zrand * chi_tot)) { // Photo electric effect - makes it a k-packet for sure. pkt_ptr->type = TYPE_NTLEPTON; pkt_ptr->absorptiontype = -4; // pkt_ptr->type = TYPE_PRE_KPKT; stats::increment(stats::COUNTER_NT_STAT_FROM_GAMMA); - } else if ((kap_compton + kap_photo_electric + kap_pair_prod) > (zrand * kap_tot)) { + } else if ((chi_compton + chi_photo_electric + chi_pair_prod) > (zrand * chi_tot)) { // It's a pair production pair_prod(pkt_ptr); } else { - printout("Failed to identify event. Gamma (1). kap_compton %g kap_photo_electric %g kap_tot %g zrand %g Abort.\n", - kap_compton, kap_photo_electric, kap_tot, zrand); + printout("Failed to identify event. Gamma (1). chi_compton %g chi_photo_electric %g chi_tot %g zrand %g Abort.\n", + chi_compton, chi_photo_electric, chi_tot, zrand); const int cellindex = pkt_ptr->where; printout( - " /*globals::cell[*/pkt_ptr->where].rho %g pkt_ptr->nu_cmf %g pkt_ptr->dir[0] %g pkt_ptr->dir[1] %g " + " globals::cell[pkt_ptr->where].rho %g pkt_ptr->nu_cmf %g pkt_ptr->dir[0] %g pkt_ptr->dir[1] %g " "pkt_ptr->dir[2] %g pkt_ptr->pos[0] %g pkt_ptr->pos[1] %g pkt_ptr->pos[2] %g \n", grid::get_rho(grid::get_cell_modelgridindex(cellindex)), pkt_ptr->nu_cmf, pkt_ptr->dir[0], pkt_ptr->dir[0], pkt_ptr->dir[1], pkt_ptr->dir[2], pkt_ptr->pos[1], pkt_ptr->pos[2]); diff --git a/globals.cc b/globals.cc index d89a90c71..0e0fa01fb 100644 --- a/globals.cc +++ b/globals.cc @@ -9,7 +9,7 @@ namespace globals { double syn_dir[3]; // vector pointing from origin to observer -struct time *time_step = nullptr; +std::unique_ptr timesteps = nullptr; double *rpkt_emiss = nullptr; /// Volume estimator for the rpkt emissivity @@ -37,8 +37,8 @@ bool do_emission_res = true; std::unique_ptr startofline; -double gamma_grey; // set to -ve for proper treatment. If possitive, then - // gamma_rays are treated as grey with this opacity. +double gamma_kappagrey; // set to -ve for proper treatment. If possitive, then + // gamma_rays are treated as grey with this opacity. double max_path_step; @@ -50,20 +50,14 @@ int opacity_case; // 0 normally, 1 for Fe-grp dependence. /// ATOMIC DATA int nlines = -1; -struct elementlist_entry *elements = nullptr; +std::vector elements; const struct linelist_entry *linelist = nullptr; struct bflist_t *bflist = nullptr; -double *spontrecombcoeff = nullptr; - -// for USE_LUT_PHOTOION = true -double *corrphotoioncoeff = nullptr; // for USE_LUT_BFHEATING = true double *bfheating_coeff = nullptr; -double *bfcooling_coeff = nullptr; - -struct rpkt_cont_opacity *kappa_rpkt_cont = nullptr; +struct rpkt_continuum_absorptioncoeffs *chi_rpkt_cont = nullptr; /// Coolinglist int ncoolingterms; @@ -99,18 +93,17 @@ int node_count = -1; // number of MPI nodes int node_id = -1; // unique number for each node constexpr int npkts = MPKTS; -int nesc = 0; // number of packets that escape during current timestep +std::atomic nesc = 0; // number of packets that escape during current timestep -double coordmax[3]; double vmax; double rmax; /// Total mass and outer velocity/radius double tmax = -1.; /// End time of current simulation double tmin = -1.; /// Start time of current simulation -int ntstep = -1; /// Number of timesteps -int itstep = -1; /// Initial timestep's number -int ftstep = -1; /// Final timestep's number -int nts_global = -1; /// Current time step +int ntimesteps = -1; /// Number of timesteps +int timestep_initial = -1; /// Initial timestep's number +int timestep_finish = -1; /// Final timestep's number +int timestep = -1; /// Current time step /// New variables for other opacity cases, still grey. double opcase3_normal; /// MK: normalisation factor for opacity_case 3 @@ -119,16 +112,50 @@ double rho_crit; /// MK: critical opacity in opacity_case 3 (could now be int total_nlte_levels; /// total number of nlte levels -bool homogeneous_abundances; - bool simulation_continued_from_saved; double nu_rfcut; int num_lte_timesteps; double cell_is_optically_thick; int num_grey_timesteps; int n_titer; -bool initial_iteration; +bool lte_iteration; int n_kpktdiffusion_timesteps; float kpktdiffusion_timescale; +void setup_mpi_vars() { +#ifdef MPI_ON + MPI_Comm_rank(MPI_COMM_WORLD, &globals::rank_global); + MPI_Comm_size(MPI_COMM_WORLD, &globals::nprocs); + + // make an intra-node communicator (group ranks that can share memory) + MPI_Comm_split_type(MPI_COMM_WORLD, MPI_COMM_TYPE_SHARED, globals::rank_global, MPI_INFO_NULL, + &globals::mpi_comm_node); + // get the local rank within this node + MPI_Comm_rank(globals::mpi_comm_node, &globals::rank_in_node); + // get the number of ranks on the node + MPI_Comm_size(globals::mpi_comm_node, &globals::node_nprocs); + MPI_Barrier(MPI_COMM_WORLD); + + // make an inter-node communicator (using local rank as the key for group membership) + MPI_Comm_split(MPI_COMM_WORLD, globals::rank_in_node, globals::rank_global, &globals::mpi_comm_internode); + + // take the node id from the local rank 0 (node master) and broadcast it + if (globals::rank_in_node == 0) { + MPI_Comm_rank(globals::mpi_comm_internode, &globals::node_id); + MPI_Comm_size(globals::mpi_comm_internode, &globals::node_count); + } + + MPI_Bcast(&globals::node_id, 1, MPI_INT, 0, globals::mpi_comm_node); + MPI_Bcast(&globals::node_count, 1, MPI_INT, 0, globals::mpi_comm_node); + +#else + globals::rank_global = 0; + globals::nprocs = 1; + globals::rank_in_node = 0; + globals::node_nprocs = 1; + globals::node_id = 0; + globals::node_count = 0; +#endif +} + } // namespace globals \ No newline at end of file diff --git a/globals.h b/globals.h index 49c02dd6c..d9cf9f6a5 100644 --- a/globals.h +++ b/globals.h @@ -1,6 +1,7 @@ #ifndef GLOBALS_H #define GLOBALS_H +#include #include #include @@ -9,28 +10,27 @@ #endif #include "artisoptions.h" -#include "boundary.h" struct time { - double start; // time at start of this timestep. [s] - double width; // Width of timestep. [s] - double mid; // Mid time in step - computed logarithmically. [s] - double gamma_dep; // cmf gamma ray energy deposition from absorption events [erg] - double gamma_dep_pathint; // cmf gamma ray energy deposition from packet trajectories [erg] - double positron_dep; // cmf positron energy deposition [erg] - double eps_positron_ana_power; // cmf positron KE energy generation rate analytical [erg/s] - double electron_dep; // cmf electron energy deposition [erg] - double electron_emission; // cmf electron KE energy generation [erg] - double eps_electron_ana_power; // cmf electron KE energy generation rate analytical [erg/s] - double alpha_dep; // cmf alpha energy deposition [erg] - double alpha_emission; // cmf alpha KE energy generation [erg] - double eps_alpha_ana_power; // cmf alpha KE energy generation rate analytical [erg/s] - double gamma_emission; // gamma decay energy generation in this timestep [erg] - double qdot_betaminus; // energy generation from beta-minus decays (including neutrinos) [erg/s/g] - double qdot_alpha; // energy generation from alpha decays (including neutrinos) [erg/s/g] - double qdot_total; // energy generation from all decays (including neutrinos) [erg/s/g] - double cmf_lum; // cmf luminosity light curve [erg] - int pellet_decays; // Number of pellets that decay in this time step. + double start; // time at start of this timestep. [s] + double width; // Width of timestep. [s] + double mid; // Mid time in step - computed logarithmically. [s] + double gamma_dep; // cmf gamma ray energy deposition from absorption events [erg] + double gamma_dep_pathint; // cmf gamma ray energy deposition from packet trajectories [erg] + double positron_dep; // cmf positron energy deposition [erg] + double eps_positron_ana_power; // cmf positron KE energy generation rate analytical [erg/s] + double electron_dep; // cmf electron energy deposition [erg] + double electron_emission; // cmf electron KE energy generation [erg] + double eps_electron_ana_power; // cmf electron KE energy generation rate analytical [erg/s] + double alpha_dep; // cmf alpha energy deposition [erg] + double alpha_emission; // cmf alpha KE energy generation [erg] + double eps_alpha_ana_power; // cmf alpha KE energy generation rate analytical [erg/s] + double gamma_emission; // gamma decay energy generation in this timestep [erg] + double qdot_betaminus; // energy generation from beta-minus decays (including neutrinos) [erg/s/g] + double qdot_alpha; // energy generation from alpha decays (including neutrinos) [erg/s/g] + double qdot_total; // energy generation from all decays (including neutrinos) [erg/s/g] + double cmf_lum; // cmf luminosity light curve [erg] + std::atomic pellet_decays; // Number of pellets that decay in this time step. }; struct bflist_t { @@ -62,7 +62,7 @@ struct groundphixslist { struct phixslist { double *groundcont_gamma_contr = nullptr; // for either USE_LUT_PHOTOION = true or !USE_LUT_BFHEATING = false - double *kappa_bf_sum = nullptr; + double *chi_bf_sum = nullptr; double *gamma_contr = nullptr; // needed for DETAILED_BF_ESTIMATORS_ON }; @@ -127,6 +127,7 @@ struct elementlist_entry { /// and their daughters. Neither it will work with OpenMP threads. float abundance; /// float initstablemeannucmass; /// Atomic mass number in multiple of MH + bool has_nlte_levels; }; struct linelist_entry { @@ -139,26 +140,22 @@ struct linelist_entry { int lowerlevelindex; /// and lower levels }; -struct nne_solution_paras { - int cellnumber; -}; - struct gslintegration_paras { const double nu_edge; const float T; const float *const photoion_xs; }; -struct rpkt_cont_opacity { - double nu; // frequency at which opacity was calculated - double total; - double es; - double ff; - double bf; - double ffheating; +struct rpkt_continuum_absorptioncoeffs { + double nu = NAN; // frequency at which opacity was calculated + double total = 0.; + double es = 0.; + double ff = 0.; + double bf = 0.; + double ffheating = 0.; // double bfheating; - int modelgridindex; - bool recalculate_required; // e.g. when cell or timestep has changed + int modelgridindex = -1; + bool recalculate_required = true; // e.g. when cell or timestep has changed }; template @@ -177,7 +174,7 @@ using chphixstargets_t = struct _chphixstargets; #include "macroatom.h" struct chlevels { - double processrates[MA_ACTION_COUNT]; + std::array processrates; chphixstargets_t *chphixstargets; double bfheatingcoeff; double population; @@ -207,7 +204,7 @@ namespace globals { extern double syn_dir[3]; // vector pointing from origin to observer -extern struct time *time_step; +extern std::unique_ptr timesteps; extern double *rpkt_emiss; @@ -235,7 +232,7 @@ extern bool do_emission_res; extern std::unique_ptr startofline; -extern double gamma_grey; +extern double gamma_kappagrey; constexpr double GREY_OP = 0.1; @@ -244,21 +241,15 @@ extern double max_path_step; extern int opacity_case; extern int nlines; -extern struct elementlist_entry *elements; +extern std::vector elements; + extern const struct linelist_entry *linelist; extern struct bflist_t *bflist; -extern double *spontrecombcoeff; - -// for USE_LUT_PHOTOION = true -extern double *corrphotoioncoeff; - // for USE_LUT_BFHEATING = true extern double *bfheating_coeff; -extern double *bfcooling_coeff; - -extern struct rpkt_cont_opacity *kappa_rpkt_cont; +extern struct rpkt_continuum_absorptioncoeffs *chi_rpkt_cont; extern int ncoolingterms; @@ -291,18 +282,17 @@ extern int node_count; extern int node_id; extern const int npkts; -extern int nesc; +extern std::atomic nesc; -extern double coordmax[3]; extern double vmax; extern double rmax; extern double tmax; extern double tmin; -extern int ntstep; -extern int itstep; -extern int ftstep; -extern int nts_global; +extern int ntimesteps; +extern int timestep_initial; +extern int timestep_finish; +extern int timestep; extern double opcase3_normal; extern double rho_crit_para; @@ -310,18 +300,18 @@ extern double rho_crit; extern int total_nlte_levels; -extern bool homogeneous_abundances; - extern bool simulation_continued_from_saved; extern double nu_rfcut; extern int num_lte_timesteps; extern double cell_is_optically_thick; extern int num_grey_timesteps; extern int n_titer; -extern bool initial_iteration; +extern bool lte_iteration; extern int n_kpktdiffusion_timesteps; extern float kpktdiffusion_timescale; +void setup_mpi_vars(); + } // namespace globals #endif // GLOBALS_H \ No newline at end of file diff --git a/grid.cc b/grid.cc index 73f8443eb..3e6037da6 100644 --- a/grid.cc +++ b/grid.cc @@ -8,18 +8,24 @@ #include #include #include +#include +#include #include #include #include +#include "artisoptions.h" #include "atomic.h" +#include "constants.h" #include "decay.h" +#include "globals.h" #include "input.h" #include "nltepop.h" #include "nonthermal.h" +#include "packet.h" #include "radfield.h" -#include "rpkt.h" #include "sn3d.h" +#include "stats.h" #include "vectors.h" namespace grid { @@ -30,15 +36,13 @@ int ncoordgrid[3]; /// propagation grid dimensions int ngrid; char coordlabel[3]; -enum model_types model_type = RHO_1D_READ; +enum gridtypes model_type = GRID_SPHERICAL1D; int npts_model = 0; // number of model grid cells int nonempty_npts_model = 0; // number of allocated non-empty model grid cells double t_model = -1.; // time at which densities in input model are correct. double *vout_model = nullptr; int ncoord_model[3]; // the model.txt input grid dimensions -double dcoord1; -double dcoord2; // spacings of a 2D model grid - must be uniform grid double min_den; // minimum model density @@ -49,9 +53,9 @@ int first_cellindex = -1; // auto-dermine first cell index in model.txt (usuall struct gridcell *cell = nullptr; -static int *mg_associated_cells = nullptr; -static int *nonemptymgi_of_mgi = nullptr; -static int *mgi_of_nonemptymgi = nullptr; +static std::vector mg_associated_cells; +static std::vector nonemptymgi_of_mgi; +static std::vector mgi_of_nonemptymgi; double *totmassradionuclide = nullptr; /// total mass of each radionuclide in the ejecta @@ -67,20 +71,17 @@ std::vector ranks_ndo; std::vector ranks_ndo_nonempty; int maxndo = -1; -auto get_mtot_input() -> double -// mass of the input model, which can be slightly different to the simulation mass -// e.g. spherical shells mapped to cartesian grid -{ - return mtot_input; -} - -auto wid_init(const int cellindex) -> double +auto wid_init(const int cellindex, const int axis) -> double // for a uniform grid this is the extent along the x,y,z coordinate (x_2 - x_1, etc.) // for spherical grid this is the radial extent (r_outer - r_inner) -// these values are for time globals::tmin +// these values are at time globals::tmin { - if constexpr (GRID_TYPE == GRID_UNIFORM) { - return 2 * globals::coordmax[0] / ncoordgrid[0]; + if constexpr (GRID_TYPE == GRID_CARTESIAN3D) { + return 2 * globals::rmax / ncoordgrid[axis]; + } + + if constexpr (GRID_TYPE == GRID_CYLINDRICAL2D) { + return (axis == 0) ? globals::rmax / ncoordgrid[axis] : 2 * globals::rmax / ncoordgrid[axis]; } if constexpr (GRID_TYPE == GRID_SPHERICAL1D) { @@ -96,14 +97,18 @@ auto get_modelcell_assocvolume_tmin(const int modelgridindex) -> double // return the model cell volume (when mapped to the propagation cells) at globals::tmin // for a uniform cubic grid this is constant { - if constexpr (GRID_TYPE == GRID_UNIFORM) { - return (wid_init(0) * wid_init(0) * wid_init(0)) * get_numassociatedcells(modelgridindex); + if constexpr (GRID_TYPE == GRID_CARTESIAN3D) { + return (wid_init(modelgridindex, 0) * wid_init(modelgridindex, 1) * wid_init(modelgridindex, 2)) * + get_numassociatedcells(modelgridindex); + } + + if constexpr (GRID_TYPE == GRID_CYLINDRICAL2D) { + return wid_init(modelgridindex, 1) * PI * + (pow(get_cellcoordmax(modelgridindex, 0), 2) - pow(get_cellcoordmin(modelgridindex, 0), 2)); } if constexpr (GRID_TYPE == GRID_SPHERICAL1D) { - return 4. / 3. * PI * - (pow(globals::tmin * vout_model[modelgridindex], 3) - - pow(globals::tmin * (modelgridindex > 0 ? vout_model[modelgridindex - 1] : 0.), 3)); + return 4. / 3. * PI * (pow(get_cellcoordmax(modelgridindex, 0), 3) - pow(get_cellcoordmin(modelgridindex, 0), 3)); } assert_always(false); @@ -113,28 +118,31 @@ auto get_gridcell_volume_tmin(const int cellindex) -> double // return the propagation cell volume at globals::tmin // for a spherical grid, the cell index is required (and should be equivalent to a modelgridindex) { - if constexpr (GRID_TYPE == GRID_UNIFORM) { - return (wid_init(0) * wid_init(0) * wid_init(0)); - } - - if constexpr (GRID_TYPE == GRID_SPHERICAL1D) { - const int mgi = get_cell_modelgridindex(cellindex); - return get_modelcell_assocvolume_tmin(mgi); + if constexpr (GRID_TYPE == GRID_CARTESIAN3D) { + return (wid_init(cellindex, 0) * wid_init(cellindex, 0) * wid_init(cellindex, 0)); } - assert_always(false); + // 2D and 1D with direct mapping to propagation cells + const int mgi = get_cell_modelgridindex(cellindex); + return get_modelcell_assocvolume_tmin(mgi); } auto get_cellcoordmax(const int cellindex, const int axis) -> double // get the minimum value of a coordinate at globals::tmin (xyz or radial coords) of a propagation cell // e.g., the minimum x position in xyz coords, or the minimum radius { - if constexpr (GRID_TYPE == GRID_UNIFORM) { - return grid::get_cellcoordmin(cellindex, axis) + grid::wid_init(0); + if constexpr (GRID_TYPE == GRID_CARTESIAN3D) { + return grid::get_cellcoordmin(cellindex, axis) + grid::wid_init(0, axis); + } + + if constexpr (GRID_TYPE == GRID_CYLINDRICAL2D) { + assert_testmodeonly(axis <= 1); + return grid::get_cellcoordmin(cellindex, axis) + grid::wid_init(cellindex, axis); } if constexpr (GRID_TYPE == GRID_SPHERICAL1D) { - return grid::get_cellcoordmin(cellindex, 0) + grid::wid_init(cellindex); + assert_testmodeonly(axis == 0); + return grid::get_cellcoordmin(cellindex, axis) + grid::wid_init(cellindex, axis); } assert_always(false); @@ -148,40 +156,54 @@ auto get_cellcoordmin(const int cellindex, const int axis) -> double // return - coordmax[axis] + (2 * get_cellcoordpointnum(cellindex, axis) * coordmax[axis] / ncoordgrid[axis]); } +static auto get_cell_r_inner(const int cellindex) -> double { + if constexpr (GRID_TYPE == GRID_SPHERICAL1D) { + return get_cellcoordmin(cellindex, 0); + } + + if constexpr (GRID_TYPE == GRID_CYLINDRICAL2D) { + const auto rcyl_inner = get_cellcoordmin(cellindex, 0); + const auto z_inner = std::min(std::abs(get_cellcoordmin(cellindex, 1)), std::abs(get_cellcoordmax(cellindex, 1))); + return std::sqrt(std::pow(rcyl_inner, 2) + std::pow(z_inner, 2)); + } + + if constexpr (GRID_TYPE == GRID_CARTESIAN3D) { + const auto x_inner = std::min(std::abs(get_cellcoordmin(cellindex, 0)), std::abs(get_cellcoordmax(cellindex, 0))); + const auto y_inner = std::min(std::abs(get_cellcoordmin(cellindex, 1)), std::abs(get_cellcoordmax(cellindex, 1))); + const auto z_inner = std::min(std::abs(get_cellcoordmin(cellindex, 2)), std::abs(get_cellcoordmax(cellindex, 2))); + return std::sqrt(std::pow(x_inner, 2) + std::pow(y_inner, 2) + std::pow(z_inner, 2)); + } +} + auto get_coordcellindexincrement(const int axis) -> int // how much do we change the cellindex to move along a coordinately axis (e.g., the x, y, z directions, or r direction) { - if constexpr (GRID_TYPE == GRID_UNIFORM) { - switch (axis) { - case 0: - return 1; + // assert_testmodeonly(axis < get_ngriddimensions()); - case 1: - return ncoordgrid[0]; + switch (axis) { + case 0: + return 1; - case 2: - return ncoordgrid[0] * ncoordgrid[1]; + case 1: + return ncoordgrid[0]; - default: - printout("invalid coordinate index %d", axis); - abort(); - return -1; - } - } + case 2: + return ncoordgrid[0] * ncoordgrid[1]; - if constexpr (GRID_TYPE == GRID_SPHERICAL1D) { - return 1; + default: + printout("invalid coordinate index %d", axis); + abort(); + return -1; } - - assert_always(false); } auto get_cellcoordpointnum(const int cellindex, const int axis) -> int // convert a cell index number into an integer (x,y,z or r) coordinate index from 0 to ncoordgrid[axis] { - if constexpr (GRID_TYPE == GRID_UNIFORM) { + if constexpr (GRID_TYPE == GRID_CARTESIAN3D || GRID_TYPE == GRID_CYLINDRICAL2D) { switch (axis) { - // increment x first, then y, then z + // 3D Cartesian: increment x first, then y, then z + // 2D Cylindrical: increment r first, then z case 0: return cellindex % ncoordgrid[0]; @@ -274,7 +296,7 @@ auto get_W(int modelgridindex) -> float { static void set_rho_tmin(int modelgridindex, float x) { modelgrid[modelgridindex].rhoinit = x; } -static void set_rho(int modelgridindex, float x) { modelgrid[modelgridindex].rho = x; } +void set_rho(int modelgridindex, float x) { modelgrid[modelgridindex].rho = x; } void set_nne(int modelgridindex, float nne) { modelgrid[modelgridindex].nne = nne; } @@ -300,9 +322,9 @@ void set_TJ(int modelgridindex, float TJ) { modelgrid[modelgridindex].TJ = TJ; } void set_W(int modelgridindex, float W) { modelgrid[modelgridindex].W = W; } -auto get_model_type() -> enum model_types { return model_type; } +auto get_model_type() -> enum gridtypes { return model_type; } -void set_model_type(enum model_types model_type_value) { model_type = model_type_value; } +void set_model_type(enum gridtypes model_type_value) { model_type = model_type_value; } auto get_npts_model() -> int // number of model grid cells @@ -324,10 +346,8 @@ static void set_npts_model(int new_npts_model) { assert_always(modelgrid == nullptr); modelgrid = static_cast(calloc(npts_model + 1, sizeof(struct modelgrid_t))); assert_always(modelgrid != nullptr); - assert_always(mg_associated_cells == nullptr); - mg_associated_cells = static_cast(malloc((npts_model + 1) * sizeof(int))); - assert_always(nonemptymgi_of_mgi == nullptr); - nonemptymgi_of_mgi = static_cast(malloc((npts_model + 1) * sizeof(int))); + mg_associated_cells.resize(npts_model + 1); + nonemptymgi_of_mgi.resize(npts_model + 1); } static void allocate_initradiobund() { @@ -400,7 +420,6 @@ static void set_cell_modelgridindex(int cellindex, int new_modelgridindex) { auto get_numassociatedcells(const int modelgridindex) -> int // number of propagation cells associated with each modelgrid cell { - assert_testmodeonly(mg_associated_cells != nullptr); assert_testmodeonly(modelgridindex <= get_npts_model()); return mg_associated_cells[modelgridindex]; } @@ -560,18 +579,28 @@ static void set_elem_stable_abund_from_total(const int mgi, const int element, c modelgrid[mgi].composition[element].abundance = isofracsum + massfracstable; } -auto get_cellradialpos(const int cellindex) -> double -// get the radial distance from the origin to the centre of the cell +static auto get_cellradialposmid(const int cellindex) -> double +// get the radial distance from the origin to the centre of the cell at time tmin { - // spherical coordinate case is trivial if (GRID_TYPE == GRID_SPHERICAL1D) { - return get_cellcoordmin(cellindex, 0) + (0.5 * wid_init(cellindex)); + // mid point radius + // return get_cellcoordmin(cellindex, 0) + (0.5 * wid_init(cellindex, 0)); + // volume averaged mean radius is slightly complex for radial shells + const double r_inner = grid::get_cellcoordmin(cellindex, 0); + const double r_outer = r_inner + grid::wid_init(cellindex, 0); + return 3. / 4 * (pow(r_outer, 4.) - pow(r_inner, 4.)) / (pow(r_outer, 3) - pow(r_inner, 3.)); + } + + if (GRID_TYPE == GRID_CYLINDRICAL2D) { + const double rcyl_mid = get_cellcoordmin(cellindex, 0) + (0.5 * wid_init(cellindex, 0)); + const double z_mid = get_cellcoordmin(cellindex, 1) + (0.5 * wid_init(cellindex, 1)); + return std::sqrt(std::pow(rcyl_mid, 2) + std::pow(z_mid, 2)); } // cubic grid requires taking the length of the 3D position vector double dcen[3]; for (int axis = 0; axis < 3; axis++) { - dcen[axis] = get_cellcoordmin(cellindex, axis) + (0.5 * wid_init(0)); + dcen[axis] = get_cellcoordmin(cellindex, axis) + (0.5 * wid_init(cellindex, axis)); } return vec_len(dcen); @@ -589,7 +618,7 @@ static void calculate_kappagrey() { double rho_sum = 0.0; double fe_sum = 0.0; double opcase3_sum = 0.0; - int const empty_cells = 0; + const int empty_cells = 0; for (int n = 0; n < ngrid; n++) { const int mgi = get_cell_modelgridindex(n); @@ -620,7 +649,7 @@ static void calculate_kappagrey() { grid_file = fopen_required("grid.out", "w"); } - /// Second pass through allows calculation of normalized kappa_grey + /// Second pass through allows calculation of normalized chi_grey double check1 = 0.0; double check2 = 0.0; for (int n = 0; n < ngrid; n++) { @@ -820,13 +849,26 @@ static void allocate_nonemptymodelcells() { // Determine the number of simulation cells associated with the model cells for (int mgi = 0; mgi < (get_npts_model() + 1); mgi++) { mg_associated_cells[mgi] = 0; + modelgrid[mgi].initial_radial_pos_sum = 0.; } for (int cellindex = 0; cellindex < ngrid; cellindex++) { + const auto radial_pos_mid = get_cellradialposmid(cellindex); + + if (FORCE_SPHERICAL_ESCAPE_SURFACE && radial_pos_mid > globals::vmax * globals::tmin) { + // for 1D models, the final shell outer v should already be at vmax + assert_always(model_type != GRID_SPHERICAL1D || cell[cellindex].modelgridindex == get_npts_model()); + cell[cellindex].modelgridindex = get_npts_model(); + } + const int mgi = get_cell_modelgridindex(cellindex); - assert_always(!(get_model_type() == RHO_3D_READ) || (get_rho_tmin(mgi) > 0) || (mgi == get_npts_model())); + assert_always(!(get_model_type() == GRID_CARTESIAN3D) || (get_rho_tmin(mgi) > 0) || (mgi == get_npts_model())); + mg_associated_cells[mgi] += 1; - assert_always(!(get_model_type() == RHO_3D_READ) || (mg_associated_cells[mgi] == 1) || (mgi == get_npts_model())); + modelgrid[mgi].initial_radial_pos_sum += radial_pos_mid; + + assert_always(!(get_model_type() == GRID_CARTESIAN3D) || (mg_associated_cells[mgi] == 1) || + (mgi == get_npts_model())); } // find number of non-empty cells and allocate nonempty list @@ -838,8 +880,7 @@ static void allocate_nonemptymodelcells() { } assert_always(nonempty_npts_model > 0); - assert_always(mgi_of_nonemptymgi == nullptr); - mgi_of_nonemptymgi = static_cast(malloc((nonempty_npts_model) * sizeof(int))); + mgi_of_nonemptymgi.resize(nonempty_npts_model); int nonemptymgi = 0; // index within list of non-empty modelgrid cells @@ -881,96 +922,61 @@ static void allocate_nonemptymodelcells() { get_nonempty_npts_model() * globals::total_nlte_levels * sizeof(double) / 1024. / 1024.); } -static void map_1dmodeltogrid() +static void map_1dmodelto3dgrid() // Map 1D spherical model grid onto propagation grid { for (int cellindex = 0; cellindex < ngrid; cellindex++) { - const double radial_pos = get_cellradialpos(cellindex); - const double vcell = radial_pos / globals::tmin; - const double vmin = 0.; - if (radial_pos < globals::rmax) { - if (GRID_TYPE == GRID_SPHERICAL1D) { - set_cell_modelgridindex(cellindex, cellindex); - } else { - int mgi = 0; + const double cellvmid = get_cellradialposmid(cellindex) / globals::tmin; + const int mgi = + std::distance(vout_model, std::find_if_not(vout_model, vout_model + get_npts_model(), + [cellvmid](double v_outer) { return v_outer < cellvmid; })); - for (int i = 0; i < (get_npts_model() - 1); i++) { - if (vout_model[mgi] < vcell) { - mgi = i + 1; - } - } - set_cell_modelgridindex(cellindex, mgi); - } - const int mgi = get_cell_modelgridindex(cellindex); - if ((vout_model[mgi] >= vmin) && (get_rho_tmin(mgi) > 0)) { - modelgrid[mgi].initial_radial_pos_sum += radial_pos; - } else { - set_cell_modelgridindex(cellindex, get_npts_model()); - } + if (mgi < get_npts_model() && modelgrid[mgi].rhoinit > 0) { + set_cell_modelgridindex(cellindex, mgi); } else { set_cell_modelgridindex(cellindex, get_npts_model()); } } } -static void map_2dmodeltogrid() +static void map_2dmodelto3dgrid() // Map 2D cylindrical model onto propagation grid { - for (int n = 0; n < ngrid; n++) { - const double radial_pos = get_cellradialpos(n); - - if (radial_pos < globals::rmax) { - double dcen[3]; - for (int d = 0; d < 3; d++) { - const double cellcoordmin = - -globals::coordmax[d] + (2 * get_cellcoordpointnum(n, d) * globals::coordmax[d] / ncoordgrid[0]); - dcen[d] = cellcoordmin + (0.5 * wid_init(0)); - } + for (int cellindex = 0; cellindex < ngrid; cellindex++) { + int mgi = get_npts_model(); // default to empty unless set - set_cell_modelgridindex(n, 0); - const double zcylindrical = dcen[2]; - dcen[2] = 0.0; - const double rcylindrical = vec_len(dcen); + // map to 3D Cartesian grid + double pos_mid[3]; + for (int d = 0; d < 3; d++) { + pos_mid[d] = (get_cellcoordmin(cellindex, d) + (0.5 * wid_init(cellindex, d))); + } - // Grid is uniform so only need to search in 1d to get r and z positions + // 2D grid is uniform so rcyl and z positions can easily be calculated + const double rcylindrical = std::sqrt(std::pow(pos_mid[0], 2) + std::pow(pos_mid[1], 2)); - int mkeep1 = 0; - for (int m = 0; m < ncoord_model[0]; m++) { - if (rcylindrical > (m * dcoord1 * globals::tmin / t_model)) { - mkeep1 = m; - // set_cell_modelgridindex(n, m + 1); - } - } + const int n_rcyl = static_cast(rcylindrical / globals::tmin / globals::vmax * ncoord_model[0]); + const int n_z = + static_cast((pos_mid[2] / globals::tmin + globals::vmax) / (2 * globals::vmax) * ncoord_model[1]); - int mkeep2 = 0; - for (int m = 0; m < ncoord_model[1]; m++) { - if (zcylindrical > (((m * dcoord2) * globals::tmin / t_model) - globals::rmax)) { - mkeep2 = m; - // set_cell_modelgridindex(n, m + 1); - } - } - set_cell_modelgridindex(n, (mkeep2 * ncoord_model[0]) + mkeep1); - modelgrid[get_cell_modelgridindex(n)].initial_radial_pos_sum += radial_pos; + if (n_rcyl >= 0 && n_rcyl < ncoord_model[0] && n_z >= 0 && n_z < ncoord_model[1]) { + mgi = (n_z * ncoord_model[0]) + n_rcyl; + } - // renorm[mkeep]++; + if (modelgrid[mgi].rhoinit > 0) { + set_cell_modelgridindex(cellindex, mgi); } else { - set_cell_modelgridindex(n, get_npts_model()); + set_cell_modelgridindex(cellindex, get_npts_model()); } } } -static void map_3dmodeltogrid() { - // propagation grid must match the input model grid exactly for 3D models - assert_always(ncoord_model[0] == ncoordgrid[0]); - assert_always(ncoord_model[1] == ncoordgrid[1]); - assert_always(ncoord_model[2] == ncoordgrid[2]); - +static void map_modeltogrid_direct() +// mgi and cellindex are interchangeable in this mode +{ for (int cellindex = 0; cellindex < ngrid; cellindex++) { - // mgi and cellindex are interchangeable in this mode - const int mgi = cellindex; - modelgrid[mgi].initial_radial_pos_sum = get_cellradialpos(cellindex); - const bool keepcell = (get_rho_tmin(mgi) > 0); - if (keepcell) { + const int mgi = cellindex; // direct mapping + + if (modelgrid[mgi].rhoinit > 0) { set_cell_modelgridindex(cellindex, mgi); } else { set_cell_modelgridindex(cellindex, get_npts_model()); @@ -984,10 +990,10 @@ static void abundances_read() { MPI_Barrier(MPI_COMM_WORLD); #endif printout("reading abundances.txt..."); - const bool threedimensional = (get_model_type() == RHO_3D_READ); + const bool threedimensional = (get_model_type() == GRID_CARTESIAN3D); /// Open the abundances file - std::ifstream abundance_file("abundances.txt"); + auto abundance_file = fstream_required("abundances.txt", std::ios::in); /// and process through the grid to read in the abundances per cell /// The abundance file should only contain information for non-empty @@ -996,20 +1002,19 @@ static void abundances_read() { /// i.e. in total one integer and 30 floats. // loop over propagation cells for 3D models, or modelgrid cells - const int npts_model = get_npts_model(); - for (int mgi = 0; mgi < npts_model; mgi++) { + for (int mgi = 0; mgi < get_npts_model(); mgi++) { std::string line; assert_always(get_noncommentline(abundance_file, line)); std::istringstream ssline(line); int cellnumberinput = -1; assert_always(ssline >> cellnumberinput); - assert_always(cellnumberinput == mgi + first_cellindex) + assert_always(cellnumberinput == mgi + first_cellindex); - // the abundances.txt file specifies the elemental mass fractions for each model cell - // (or proportial to mass frac, e.g. element densities because they will be normalised anyway) - // The abundances begin with hydrogen, helium, etc, going as far up the atomic numbers as required - double normfactor = 0.; + // the abundances.txt file specifies the elemental mass fractions for each model cell + // (or proportial to mass frac, e.g. element densities because they will be normalised anyway) + // The abundances begin with hydrogen, helium, etc, going as far up the atomic numbers as required + double normfactor = 0.; float abundances_in[150] = {0.}; for (int anumber = 1; anumber <= 150; anumber++) { abundances_in[anumber - 1] = 0.; @@ -1040,7 +1045,6 @@ static void abundances_read() { } } - abundance_file.close(); #ifdef MPI_ON // barrier to make sure node master has set values in node shared memory MPI_Barrier(MPI_COMM_WORLD); @@ -1048,13 +1052,8 @@ static void abundances_read() { printout("done.\n"); } -static auto str_starts_with(const std::string &str, const std::string &strprefix) -> bool { - // return true if str starts with strprefix - return (str.rfind(strprefix, 0) == 0); -} - -static void read_model_headerline(const std::string &line, std::vector &zlist, std::vector &alist, - std::vector &columnname) { +static void parse_model_headerline(const std::string &line, std::vector &zlist, std::vector &alist, + std::vector &colnames) { // custom header line std::istringstream iss(line); std::string token; @@ -1062,7 +1061,7 @@ static void read_model_headerline(const std::string &line, std::vector &zli int columnindex = -1; while (std::getline(iss, token, ' ')) { - if (std::all_of(token.begin(), token.end(), isspace)) { // skip whitespace tokens + if (std::ranges::all_of(token, isspace)) { // skip whitespace tokens continue; } @@ -1072,172 +1071,181 @@ static void read_model_headerline(const std::string &line, std::vector &zli assert_always(columnindex == 0); } else if (token == "velocity_outer") { assert_always(columnindex == 1); + } else if (token == "vel_r_max_kmps") { + assert_always(columnindex == 1); + } else if (token.starts_with("pos_")) { + continue; } else if (token == "logrho") { // 1D models have log10(rho [g/cm3]) assert_always(columnindex == 2); - assert_always(get_model_type() == RHO_1D_READ); + assert_always(get_model_type() == GRID_SPHERICAL1D); } else if (token == "rho") { - // 2D amd 3D models have rho [g/cm3] - assert_always(columnindex == 4); - assert_always(get_model_type() != RHO_1D_READ); + // 2D and 3D models have rho [g/cm3] + assert_always(get_model_type() != GRID_SPHERICAL1D); + assert_always((columnindex == 4 && get_model_type() == GRID_CARTESIAN3D) || + (columnindex == 3 && get_model_type() == GRID_CYLINDRICAL2D)); continue; } else if (token == "X_Fegroup") { - continue; - } else if (token == "X_Ni56") { - continue; - } else if (token == "X_Co56") { - continue; - } else if (token == "X_Fe52") { - continue; - } else if (token == "X_Cr48") { - continue; - } else if (token == "X_Ni57") { - continue; - } else if (token == "X_Co57") { - continue; - } else if (str_starts_with(token, "pos_")) { - continue; + colnames.push_back(token); + zlist.push_back(-1); + alist.push_back(-1); + } else if (token.starts_with("X_")) { + colnames.push_back(token); + const int z = decay::get_nucstring_z(token.substr(2)); // + 2 skips the 'X_' + const int a = decay::get_nucstring_a(token.substr(2)); + assert_always(z >= 0); + assert_always(a >= 0); + // printout("Custom column: '%s' Z %d A %d\n", token.c_str(), z, a); + zlist.push_back(z); + alist.push_back(a); } else { - assert_always(get_model_type() != RHO_1D_READ || columnindex >= 10); - assert_always(get_model_type() != RHO_3D_READ || columnindex >= 12); - - columnname.push_back(token); - - if (str_starts_with(token, "X_")) { - const int z = decay::get_nucstring_z(token.substr(2)); // + 2 skips the 'X_' - const int a = decay::get_nucstring_a(token.substr(2)); - assert_always(z >= 0); - assert_always(a >= 0); - // printout("Custom column: '%s' Z %d A %d\n", token.c_str(), z, a); - zlist.push_back(z); - alist.push_back(a); - } else { - // printout("Custom column: '%s' Z %d A %d\n", token.c_str(), -1, -1); - zlist.push_back(-1); - alist.push_back(-1); - } + // printout("Custom column: '%s' Z %d A %d\n", token.c_str(), -1, -1); + colnames.push_back(token); + zlist.push_back(-1); + alist.push_back(-1); } } +} - // alternative: - // while(iss >> token) - // { - // printout("Custom header column: %s\n", token.c_str()); - // columns.push_back(token); - // } - - // for(std::vector::iterator it = columns.begin(); it != columns.end(); ++it) - // { - // printout("Repeat of Custom header column: %s\n", it->c_str()); - // } +static auto get_token_count(std::string &line) -> int { + std::string token; + int abundcolcount = 0; + auto ssline = std::istringstream(line); + while (std::getline(ssline, token, ' ')) { + if (!std::ranges::all_of(token, isspace)) { // skip whitespace tokens + abundcolcount++; + } + } + return abundcolcount; } -static void read_model_radioabundances(std::ifstream &fmodel, std::string &line, const int linepos, const int mgi, - const bool keepcell, std::vector &colnames, - std::vector &nucindexlist) { - bool one_line_per_cell = false; +static void read_model_radioabundances(std::fstream &fmodel, std::istringstream &ssline_in, const int mgi, + const bool keepcell, const std::vector &colnames, + const std::vector &nucindexlist, const bool one_line_per_cell) { + std::string line; + if (!one_line_per_cell) { + assert_always(std::getline(fmodel, line)); + } - if (linepos < static_cast(line.length())) { - // still more line is remaining, so any non-whitespace chars mean that - // the abundances are on the same line - line = line.substr(linepos); - for (const char &c : line) { - if (isspace(c) == 0) { - one_line_per_cell = true; - break; + auto ssline = one_line_per_cell ? std::move(ssline_in) : std::istringstream(line); + + if (!keepcell) { + return; + } + + for (size_t i = 0; i < colnames.size(); i++) { + double valuein = 0.; + assert_always(ssline >> valuein); // usually a mass fraction, but now can be anything + + if (nucindexlist[i] >= 0) { + assert_testmodeonly(valuein >= 0.); + assert_testmodeonly(valuein <= 1.); + set_modelinitradioabund(mgi, nucindexlist[i], valuein); + } else if (colnames[i] == "X_Fegroup") { + set_ffegrp(mgi, valuein); + } else if (colnames[i] == "cellYe") { + set_initelectronfrac(mgi, valuein); + } else if (colnames[i] == "q") { + // use value for t_model and adjust to tmin with expansion factor + set_initenergyq(mgi, valuein * t_model / globals::tmin); + } else if (colnames[i] == "tracercount") { + ; + } else { + if (mgi == 0) { + printout("WARNING: ignoring column '%s' nucindex %d valuein[mgi=0] %lg\n", colnames[i].c_str(), nucindexlist[i], + valuein); } } } + double valuein = 0.; + assert_always(!(ssline >> valuein)); // should be no tokens left! +} - if (one_line_per_cell) { - if (mgi == 0) { - printout("model.txt has has single line per cell format\n"); - } +static auto read_model_columns(std::fstream &fmodel) -> std::tuple, std::vector, bool> { + auto pos_data_start = fmodel.tellg(); // get position in case we need to undo getline + + std::vector zlist; + std::vector alist; + std::vector colnames; + + std::string line; + std::getline(fmodel, line); + + std::string headerline; + + const bool header_specified = lineiscommentonly(line); + + if (header_specified) { + // line is the header + headerline = line; + pos_data_start = fmodel.tellg(); + std::getline(fmodel, line); } else { - // we reached the end of this line before abundances were read - if (mgi == 0) { - printout("model.txt has has two lines per cell format\n"); + // line is not a comment, so it must be the first line of data + // add a default header for unlabelled columns + switch (model_type) { + case GRID_SPHERICAL1D: + headerline = "#inputcellid vel_r_max_kmps logrho"; + break; + case GRID_CYLINDRICAL2D: + headerline = "#inputcellid pos_rcyl_mid pos_z_mid rho"; + break; + case GRID_CARTESIAN3D: + headerline = "#inputcellid pos_x_min pos_y_min pos_z_min rho"; + break; } - assert_always(std::getline(fmodel, line)); + headerline += " X_Fegroup X_Ni56 X_Co56 X_Fe52 X_Cr48"; } - std::istringstream ssline(line); - double f56ni_model = 0.; - double f56co_model = 0.; - double ffegrp_model = 0.; - double f48cr_model = 0.; - double f52fe_model = 0.; - double f57ni_model = 0.; - double f57co_model = 0.; - const int items_read = sscanf(line.c_str(), "%lg %lg %lg %lg %lg %lg %lg", &ffegrp_model, &f56ni_model, &f56co_model, - &f52fe_model, &f48cr_model, &f57ni_model, &f57co_model); + int colcount = get_token_count(line); + const bool one_line_per_cell = (colcount >= get_token_count(headerline)); - if (items_read == 5 || items_read == 7) { - if (items_read == 7 && mgi == 0) { - printout("Found Ni57 and Co57 abundance columns in model.txt\n"); - } + printout("model.txt has %s line per cell format\n", one_line_per_cell ? "one" : "two"); - // printout("mgi %d ni56 %g co56 %g fe52 %g cr48 %g ni57 %g co57 %g\n", - // mgi, f56ni_model, f56co_model, f52fe_model, f48cr_model, f57ni_model, f57co_model); + if (!one_line_per_cell) { // add columns from the second line + std::getline(fmodel, line); + colcount += get_token_count(line); + } - if (keepcell) { - set_modelinitradioabund(mgi, decay::get_nucindex(28, 56), f56ni_model); - set_modelinitradioabund(mgi, decay::get_nucindex(27, 56), f56co_model); - set_modelinitradioabund(mgi, decay::get_nucindex(26, 52), f52fe_model); - set_modelinitradioabund(mgi, decay::get_nucindex(24, 48), f48cr_model); - set_modelinitradioabund(mgi, decay::get_nucindex(23, 48), 0.); - set_modelinitradioabund(mgi, decay::get_nucindex(28, 57), f57ni_model); - set_modelinitradioabund(mgi, decay::get_nucindex(27, 57), f57co_model); - - set_ffegrp(mgi, ffegrp_model); - - if (items_read == 7) { - for (int i = 0; i < items_read; i++) { - double abundin = 0.; - assert_always(ssline >> abundin); // ignore - } + if (!header_specified && colcount > get_token_count(headerline)) { + headerline += " X_Ni57 X_Co57"; + } - for (int i = 0; i < static_cast(colnames.size()); i++) { - double valuein = 0.; - assert_always(ssline >> valuein); // usually a mass fraction, but now can be anything - if (nucindexlist[i] >= 0) { - set_modelinitradioabund(mgi, nucindexlist[i], valuein); - } else if (colnames[i] == "cellYe") { - set_initelectronfrac(mgi, valuein); - } else if (colnames[i] == "q") { - // use value for t_model and adjust to tmin with expansion factor - set_initenergyq(mgi, valuein * t_model / globals::tmin); - } else if (colnames[i] == "tracercount") { - ; - } else { - printout("Not sure what to do with column %s nucindex %d valuein %lg\n", colnames[i].c_str(), - nucindexlist[i], valuein); - assert_always(false); - } - } - double valuein = 0.; - assert_always(!(ssline >> valuein)); // should be no tokens left! - } - } + assert_always(colcount == get_token_count(headerline)); + + fmodel.seekg(pos_data_start); // get back to start of data + + if (header_specified) { + printout("model.txt has header line: %s\n", headerline.c_str()); } else { - printout("Unexpected number of values in model.txt. items_read = %d\n", items_read); - printout("line: %s\n", line.c_str()); - abort(); + printout("model.txt has no header line. Using default: %s\n", headerline.c_str()); + } + + parse_model_headerline(headerline, zlist, alist, colnames); + + decay::init_nuclides(zlist, alist); + + std::vector nucindexlist(zlist.size()); + for (std::size_t i = 0; i < zlist.size(); i++) { + nucindexlist[i] = (zlist[i] > 0) ? decay::get_nucindex(zlist[i], alist[i]) : -1; } + + allocate_initradiobund(); + + return std::make_tuple(colnames, nucindexlist, one_line_per_cell); } static void read_1d_model() // Read in a 1D spherical model { - std::ifstream fmodel("model.txt"); - assert_always(fmodel.is_open()); + auto fmodel = fstream_required("model.txt", std::ios::in); std::string line; // 1st read the number of data points in the table of input model. int npts_model_in = 0; assert_always(get_noncommentline(fmodel, line)); - std::stringstream(line) >> npts_model_in; + std::istringstream(line) >> npts_model_in; set_npts_model(npts_model_in); ncoord_model[0] = npts_model_in; @@ -1247,7 +1255,7 @@ static void read_1d_model() // Now read the time (in days) at which the model is specified. double t_model_days = NAN; assert_always(get_noncommentline(fmodel, line)); - std::stringstream(line) >> t_model_days; + std::istringstream(line) >> t_model_days; t_model = t_model_days * DAY; // Now read in the lines of the model. Each line has 5 entries: the @@ -1257,38 +1265,19 @@ static void read_1d_model() // in the cell (float). For now, the last number is recorded but never // used. - std::vector zlist; - std::vector alist; - std::vector colnames; - std::streampos const oldpos = fmodel.tellg(); // get position in case we need to undo getline - std::getline(fmodel, line); - if (lineiscommentonly(line)) { - read_model_headerline(line, zlist, alist, colnames); - } else { - fmodel.seekg(oldpos); // undo getline because it was data, not a header line - } - - decay::init_nuclides(zlist, alist); - allocate_initradiobund(); - - std::vector nucindexlist(zlist.size()); - for (int i = 0; i < static_cast(zlist.size()); i++) { - nucindexlist[i] = (zlist[i] > 0) ? decay::get_nucindex(zlist[i], alist[i]) : -1; - } + const auto [colnames, nucindexlist, one_line_per_cell] = read_model_columns(fmodel); int mgi = 0; while (std::getline(fmodel, line)) { - std::istringstream const ssline(line); double vout_kmps = NAN; double log_rho = NAN; int cellnumberin = 0; - int linepos = 0; - - const int items_read = sscanf(line.c_str(), "%d %lg %lg%n", &cellnumberin, &vout_kmps, &log_rho, &linepos); + std::istringstream ssline(line); - if (items_read == 3) { + if (ssline >> cellnumberin >> vout_kmps >> log_rho) { if (mgi == 0) { first_cellindex = cellnumberin; + printout("first_cellindex %d\n", first_cellindex); } assert_always(cellnumberin == mgi + first_cellindex); @@ -1298,12 +1287,11 @@ static void read_1d_model() set_rho_tmin(mgi, rho_tmin); set_rho(mgi, rho_tmin); } else { - printout("Unexpected number of values in model.txt. items_read = %d\n", items_read); + printout("Unexpected number of values in model.txt\n"); printout("line: %s\n", line.c_str()); assert_always(false); } - - read_model_radioabundances(fmodel, line, linepos, mgi, true, colnames, nucindexlist); + read_model_radioabundances(fmodel, ssline, mgi, true, colnames, nucindexlist, one_line_per_cell); mgi += 1; if (mgi == get_npts_model()) { @@ -1312,60 +1300,38 @@ static void read_1d_model() } if (mgi != get_npts_model()) { - printout("ERROR in model.txt. Found %d only cells instead of %d expected.\n", mgi - 1, get_npts_model()); + printout("ERROR in model.txt. Found only %d cells instead of %d expected.\n", mgi - 1, get_npts_model()); abort(); } - fmodel.close(); - globals::vmax = vout_model[get_npts_model() - 1]; } static void read_2d_model() // Read in a 2D axisymmetric spherical coordinate model { - std::ifstream fmodel("model.txt"); - assert_always(fmodel.is_open()); + auto fmodel = fstream_required("model.txt", std::ios::in); std::string line; // 1st read the number of data points in the table of input model. assert_always(get_noncommentline(fmodel, line)); - std::stringstream(line) >> ncoord_model[0] >> ncoord_model[1]; // r and z (cylindrical polar) + std::istringstream(line) >> ncoord_model[0] >> ncoord_model[1]; // r and z (cylindrical polar) + ncoord_model[2] = 0.; set_npts_model(ncoord_model[0] * ncoord_model[1]); // Now read the time (in days) at which the model is specified. double t_model_days = NAN; assert_always(get_noncommentline(fmodel, line)); - std::stringstream(line) >> t_model_days; + std::istringstream(line) >> t_model_days; t_model = t_model_days * DAY; /// Now read in vmax for the model (in cm s^-1). assert_always(get_noncommentline(fmodel, line)); - std::stringstream(line) >> globals::vmax; + std::istringstream(line) >> globals::vmax; - dcoord1 = globals::vmax * t_model / ncoord_model[0]; // dr for input model - dcoord2 = 2. * globals::vmax * t_model / ncoord_model[1]; // dz for input model - - std::vector zlist; - std::vector alist; - std::vector colnames; - std::streampos const oldpos = fmodel.tellg(); // get position in case we need to undo getline - std::getline(fmodel, line); - if (lineiscommentonly(line)) { - read_model_headerline(line, zlist, alist, colnames); - } else { - fmodel.seekg(oldpos); // undo getline because it was data, not a header line - } - - decay::init_nuclides(zlist, alist); - allocate_initradiobund(); - - std::vector nucindexlist(zlist.size()); - for (int i = 0; i < static_cast(zlist.size()); i++) { - nucindexlist[i] = (zlist[i] > 0) ? decay::get_nucindex(zlist[i], alist[i]) : -1; - } + const auto [colnames, nucindexlist, one_line_per_cell] = read_model_columns(fmodel); // Now read in the model. Each point in the model has two lines of input. // First is an index for the cell then its r-mid point then its z-mid point @@ -1373,33 +1339,42 @@ static void read_2d_model() // Second is the total FeG mass, initial 56Ni mass, initial 56Co mass int mgi = 0; + int nonemptymgi = 0; while (std::getline(fmodel, line)) { int cellnumberin = 0; float cell_r_in = NAN; float cell_z_in = NAN; double rho_tmodel = NAN; - int linepos = 0; - - assert_always( - sscanf(line.c_str(), "%d %g %g %lg%n", &cellnumberin, &cell_r_in, &cell_z_in, &rho_tmodel, &linepos) == 4); + std::istringstream ssline(line); + assert_always(ssline >> cellnumberin >> cell_r_in >> cell_z_in >> rho_tmodel); if (mgi == 0) { first_cellindex = cellnumberin; } assert_always(cellnumberin == mgi + first_cellindex); - const int ncoord1 = (mgi % ncoord_model[0]); - const double r_cylindrical = (ncoord1 + 0.5) * dcoord1; - assert_always(fabs(cell_r_in / r_cylindrical - 1) < 1e-3); - const int ncoord2 = (mgi / ncoord_model[0]); - const double z = -globals::vmax * t_model + ((ncoord2 + 0.5) * dcoord2); - assert_always(fabs(cell_z_in / z - 1) < 1e-3); + const int n_rcyl = (mgi % ncoord_model[0]); + const double pos_r_cyl_mid = (n_rcyl + 0.5) * globals::vmax * t_model / ncoord_model[0]; + assert_always(fabs(cell_r_in / pos_r_cyl_mid - 1) < 1e-3); + const int n_z = (mgi / ncoord_model[0]); + const double pos_z_mid = globals::vmax * t_model * (-1 + 2 * (n_z + 0.5) / ncoord_model[1]); + assert_always(fabs(cell_z_in / pos_z_mid - 1) < 1e-3); + + if (rho_tmodel < 0) { + printout("negative input density %g %d\n", rho_tmodel, mgi); + abort(); + } + const bool keepcell = (rho_tmodel > 0); const double rho_tmin = rho_tmodel * pow(t_model / globals::tmin, 3); set_rho_tmin(mgi, rho_tmin); set_rho(mgi, rho_tmin); - read_model_radioabundances(fmodel, line, linepos, mgi, true, colnames, nucindexlist); + read_model_radioabundances(fmodel, ssline, mgi, keepcell, colnames, nucindexlist, one_line_per_cell); + + if (keepcell) { + nonemptymgi++; + } mgi++; } @@ -1409,15 +1384,13 @@ static void read_2d_model() abort(); } - fmodel.close(); + printout("Effectively used model grid cells: %d\n", nonemptymgi); } static void read_3d_model() /// Subroutine to read in a 3-D model. { - printout("reading 3D model.txt...\n"); - std::ifstream fmodel("model.txt"); - assert_always(fmodel.is_open()); + auto fmodel = fstream_required("model.txt", std::ios::in); std::string line; @@ -1425,7 +1398,7 @@ static void read_3d_model() /// This MUST be the same number as the maximum number of points used in the grid - if not, abort. int npts_model_in = 0; assert_always(get_noncommentline(fmodel, line)); - std::stringstream(line) >> npts_model_in; + std::istringstream(line) >> npts_model_in; set_npts_model(npts_model_in); ncoord_model[0] = ncoord_model[1] = ncoord_model[2] = static_cast(round(pow(npts_model_in, 1 / 3.))); @@ -1439,14 +1412,14 @@ static void read_3d_model() double t_model_days = NAN; assert_always(get_noncommentline(fmodel, line)); - std::stringstream(line) >> t_model_days; + std::istringstream(line) >> t_model_days; t_model = t_model_days * DAY; /// Now read in vmax for the model (in cm s^-1). assert_always(get_noncommentline(fmodel, line)); - std::stringstream(line) >> globals::vmax; + std::istringstream(line) >> globals::vmax; - double const xmax_tmodel = globals::vmax * t_model; + const double xmax_tmodel = globals::vmax * t_model; /// Now read in the lines of the model. min_den = -1.; @@ -1456,24 +1429,7 @@ static void read_3d_model() bool posmatch_xyz = true; bool posmatch_zyx = true; - std::vector zlist; - std::vector alist; - std::vector colnames; - std::streampos const oldpos = fmodel.tellg(); // get position in case we need to undo getline - std::getline(fmodel, line); - if (lineiscommentonly(line)) { - read_model_headerline(line, zlist, alist, colnames); - } else { - fmodel.seekg(oldpos); // undo getline because it was data, not a header line - } - - decay::init_nuclides(zlist, alist); - allocate_initradiobund(); - - std::vector nucindexlist(zlist.size()); - for (int i = 0; i < static_cast(zlist.size()); i++) { - nucindexlist[i] = (zlist[i] > 0) ? decay::get_nucindex(zlist[i], alist[i]) : -1; - } + const auto [colnames, nucindexlist, one_line_per_cell] = read_model_columns(fmodel); // mgi is the index to the model grid - empty cells are sent to special value get_npts_model(), // otherwise each input cell is one modelgrid cell @@ -1483,10 +1439,9 @@ static void read_3d_model() int cellnumberin = 0; float cellpos_in[3]; float rho_model = NAN; - int linepos = 0; - int const items_read = sscanf(line.c_str(), "%d %g %g %g %g%n", &cellnumberin, &cellpos_in[0], &cellpos_in[1], - &cellpos_in[2], &rho_model, &linepos); - assert_always(items_read == 5); + std::istringstream ssline(line); + + assert_always(ssline >> cellnumberin >> cellpos_in[0] >> cellpos_in[1] >> cellpos_in[2] >> rho_model); // printout("cell %d, posz %g, posy %g, posx %g, rho %g, rho_init %g\n",dum1,dum3,dum4,dum5,rho_model,rho_model* // pow( (t_model/globals::tmin), 3.)); @@ -1530,7 +1485,7 @@ static void read_3d_model() min_den = rho_model; } - read_model_radioabundances(fmodel, line, linepos, mgi, keepcell, colnames, nucindexlist); + read_model_radioabundances(fmodel, ssline, mgi, keepcell, colnames, nucindexlist, one_line_per_cell); if (keepcell) { nonemptymgi++; @@ -1552,11 +1507,7 @@ static void read_3d_model() } printout("min_den %g [g/cm3]\n", min_den); - printout("Effectively used model grid cells %d\n", nonemptymgi); - - /// Now, set actual size of the modelgrid to the number of non-empty cells. - - fmodel.close(); + printout("Effectively used model grid cells: %d\n", nonemptymgi); } static void calc_modelinit_totmassradionuclides() { @@ -1571,31 +1522,29 @@ static void calc_modelinit_totmassradionuclides() { totmassradionuclide[nucindex] = 0.; } - int n1 = 0; + const double dcoord_rcyl = globals::vmax * t_model / ncoord_model[0]; // dr for input model + const double dcoord_z = 2. * globals::vmax * t_model / ncoord_model[1]; // dz for input model + for (int mgi = 0; mgi < get_npts_model(); mgi++) { if (get_rho_tmin(mgi) <= 0.) { continue; } double cellvolume = 0.; - if (get_model_type() == RHO_1D_READ) { + if (get_model_type() == GRID_SPHERICAL1D) { const double v_inner = (mgi == 0) ? 0. : vout_model[mgi - 1]; // mass_in_shell = rho_model[mgi] * (pow(vout_model[mgi], 3) - pow(v_inner, 3)) * 4 * PI * pow(t_model, 3) / 3.; cellvolume = (pow(vout_model[mgi], 3) - pow(v_inner, 3)) * 4 * PI * pow(globals::tmin, 3) / 3.; - } else if (get_model_type() == RHO_2D_READ) { - cellvolume = pow(globals::tmin / t_model, 3) * ((2 * n1) + 1) * PI * dcoord2 * pow(dcoord1, 2.); - n1++; - if (n1 == ncoord_model[0]) { - n1 = 0; - } - } else if (get_model_type() == RHO_3D_READ) { + } else if (get_model_type() == GRID_CYLINDRICAL2D) { + const int n_r = mgi % ncoord_model[0]; + cellvolume = pow(globals::tmin / t_model, 3) * dcoord_z * PI * + (pow((n_r + 1) * dcoord_rcyl, 2.) - pow(n_r * dcoord_rcyl, 2.)); + } else if (get_model_type() == GRID_CARTESIAN3D) { /// Assumes cells are cubes here - all same volume. cellvolume = pow((2 * globals::vmax * globals::tmin), 3.) / (ncoordgrid[0] * ncoordgrid[1] * ncoordgrid[2]); } else { printout("Unknown model type %d in function %s\n", get_model_type(), __func__); abort(); } - // can use grid::get_modelcell_assocvolume_tmin(mgi) to get actual simulated volume (with slight error versus - // input) const double mass_in_shell = get_rho_tmin(mgi) * cellvolume; @@ -1619,25 +1568,20 @@ static void calc_modelinit_totmassradionuclides() { void read_ejecta_model() { switch (get_model_type()) { - case RHO_UNIFORM: { - assert_always(false); // needs to be reimplemented using spherical coordinate mode - break; - } - - case RHO_1D_READ: { + case GRID_SPHERICAL1D: { printout("Read 1D model\n"); read_1d_model(); break; } - case RHO_2D_READ: { + case GRID_CYLINDRICAL2D: { printout("Read 2D model\n"); read_2d_model(); break; } - case RHO_3D_READ: { + case GRID_CARTESIAN3D: { printout("Read 3D model\n"); read_3d_model(); @@ -1657,8 +1601,6 @@ void read_ejecta_model() { printout("tmin %g [s] = %.2f [d]\n", globals::tmin, globals::tmin / 86400.); printout("rmax %g [cm] (at t=tmin)\n", globals::rmax); - globals::coordmax[0] = globals::coordmax[1] = globals::coordmax[2] = globals::rmax; - globals::rpkt_emiss = static_cast(calloc((get_npts_model() + 1), sizeof(double))); if constexpr (USE_LUT_PHOTOION) { @@ -1701,9 +1643,9 @@ static void read_grid_restart_data(const int timestep) { printout("READIN GRID SNAPSHOT from %s\n", filename); FILE *gridsave_file = fopen_required(filename, "r"); - int ntstep_in = -1; - assert_always(fscanf(gridsave_file, "%d ", &ntstep_in) == 1); - assert_always(ntstep_in == globals::ntstep); + int ntimesteps_in = -1; + assert_always(fscanf(gridsave_file, "%d ", &ntimesteps_in) == 1); + assert_always(ntimesteps_in == globals::ntimesteps); int nprocs_in = -1; assert_always(fscanf(gridsave_file, "%d ", &nprocs_in) == 1); @@ -1713,16 +1655,18 @@ static void read_grid_restart_data(const int timestep) { assert_always(fscanf(gridsave_file, "%d ", &nthreads_in) == 1); assert_always(nthreads_in == get_num_threads()); - for (int nts = 0; nts < globals::ntstep; nts++) { + for (int nts = 0; nts < globals::ntimesteps; nts++) { + int pellet_decays = 0.; assert_always(fscanf(gridsave_file, "%la %la %la %la %la %la %la %la %la %la %la %la %la %la %la %d ", - &globals::time_step[nts].gamma_dep, &globals::time_step[nts].gamma_dep_pathint, - &globals::time_step[nts].positron_dep, &globals::time_step[nts].eps_positron_ana_power, - &globals::time_step[nts].electron_dep, &globals::time_step[nts].electron_emission, - &globals::time_step[nts].eps_electron_ana_power, &globals::time_step[nts].alpha_dep, - &globals::time_step[nts].alpha_emission, &globals::time_step[nts].eps_alpha_ana_power, - &globals::time_step[nts].qdot_betaminus, &globals::time_step[nts].qdot_alpha, - &globals::time_step[nts].qdot_total, &globals::time_step[nts].gamma_emission, - &globals::time_step[nts].cmf_lum, &globals::time_step[nts].pellet_decays) == 16); + &globals::timesteps[nts].gamma_dep, &globals::timesteps[nts].gamma_dep_pathint, + &globals::timesteps[nts].positron_dep, &globals::timesteps[nts].eps_positron_ana_power, + &globals::timesteps[nts].electron_dep, &globals::timesteps[nts].electron_emission, + &globals::timesteps[nts].eps_electron_ana_power, &globals::timesteps[nts].alpha_dep, + &globals::timesteps[nts].alpha_emission, &globals::timesteps[nts].eps_alpha_ana_power, + &globals::timesteps[nts].qdot_betaminus, &globals::timesteps[nts].qdot_alpha, + &globals::timesteps[nts].qdot_total, &globals::timesteps[nts].gamma_emission, + &globals::timesteps[nts].cmf_lum, &pellet_decays) == 16); + globals::timesteps[nts].pellet_decays = pellet_decays; } int timestep_in = 0; @@ -1739,8 +1683,8 @@ static void read_grid_restart_data(const int timestep) { double rpkt_emiss = 0.; if (get_numassociatedcells(mgi) > 0) { - assert_always( - fscanf(gridsave_file, "%d %a %a %a %a %d %la", &mgi_in, &T_R, &T_e, &W, &T_J, &thick, &rpkt_emiss) == 7); + assert_always(fscanf(gridsave_file, "%d %a %a %a %a %d %la %a %a", &mgi_in, &T_R, &T_e, &W, &T_J, &thick, + &rpkt_emiss, &modelgrid[mgi].nne, &modelgrid[mgi].nnetot) == 9); if (mgi_in != mgi) { printout("[fatal] read_grid_restart_data: cell mismatch in reading input gridsave.dat ... abort\n"); @@ -1766,7 +1710,7 @@ static void read_grid_restart_data(const int timestep) { for (int element = 0; element < get_nelements(); element++) { const int nions = get_nions(element); for (int ion = 0; ion < nions; ion++) { - const int estimindex = mgi * get_nelements() * get_max_nions() + element * get_max_nions() + ion; + const int estimindex = get_ionestimindex(mgi, element, ion); assert_always(fscanf(gridsave_file, " %la %la", &globals::corrphotoionrenorm[estimindex], &globals::gammaestimator[estimindex]) == 2); } @@ -1790,20 +1734,20 @@ void write_grid_restart_data(const int timestep) { FILE *gridsave_file = fopen_required(filename, "w"); - fprintf(gridsave_file, "%d ", globals::ntstep); + fprintf(gridsave_file, "%d ", globals::ntimesteps); fprintf(gridsave_file, "%d ", globals::nprocs); fprintf(gridsave_file, "%d ", get_num_threads()); - for (int nts = 0; nts < globals::ntstep; nts++) { + for (int nts = 0; nts < globals::ntimesteps; nts++) { fprintf(gridsave_file, "%la %la %la %la %la %la %la %la %la %la %la %la %la %la %la %d ", - globals::time_step[nts].gamma_dep, globals::time_step[nts].gamma_dep_pathint, - globals::time_step[nts].positron_dep, globals::time_step[nts].eps_positron_ana_power, - globals::time_step[nts].electron_dep, globals::time_step[nts].electron_emission, - globals::time_step[nts].eps_electron_ana_power, globals::time_step[nts].alpha_dep, - globals::time_step[nts].alpha_emission, globals::time_step[nts].eps_alpha_ana_power, - globals::time_step[nts].qdot_betaminus, globals::time_step[nts].qdot_alpha, - globals::time_step[nts].qdot_total, globals::time_step[nts].gamma_emission, globals::time_step[nts].cmf_lum, - globals::time_step[nts].pellet_decays); + globals::timesteps[nts].gamma_dep, globals::timesteps[nts].gamma_dep_pathint, + globals::timesteps[nts].positron_dep, globals::timesteps[nts].eps_positron_ana_power, + globals::timesteps[nts].electron_dep, globals::timesteps[nts].electron_emission, + globals::timesteps[nts].eps_electron_ana_power, globals::timesteps[nts].alpha_dep, + globals::timesteps[nts].alpha_emission, globals::timesteps[nts].eps_alpha_ana_power, + globals::timesteps[nts].qdot_betaminus, globals::timesteps[nts].qdot_alpha, + globals::timesteps[nts].qdot_total, globals::timesteps[nts].gamma_emission, globals::timesteps[nts].cmf_lum, + globals::timesteps[nts].pellet_decays.load()); } fprintf(gridsave_file, "%d ", timestep); @@ -1813,15 +1757,15 @@ void write_grid_restart_data(const int timestep) { if (nonemptycell) { assert_always(globals::rpkt_emiss[mgi] >= 0.); - fprintf(gridsave_file, "%d %a %a %a %a %d %la", mgi, get_TR(mgi), get_Te(mgi), get_W(mgi), get_TJ(mgi), - modelgrid[mgi].thick, globals::rpkt_emiss[mgi]); + fprintf(gridsave_file, "%d %a %a %a %a %d %la %a %a", mgi, get_TR(mgi), get_Te(mgi), get_W(mgi), get_TJ(mgi), + modelgrid[mgi].thick, globals::rpkt_emiss[mgi], modelgrid[mgi].nne, modelgrid[mgi].nnetot); } if constexpr (USE_LUT_PHOTOION) { for (int element = 0; element < get_nelements(); element++) { const int nions = get_nions(element); for (int ion = 0; ion < nions; ion++) { - const int estimindex = mgi * get_nelements() * get_max_nions() + element * get_max_nions() + ion; + const int estimindex = get_ionestimindex(mgi, element, ion); fprintf(gridsave_file, " %la %la", (nonemptycell ? globals::corrphotoionrenorm[estimindex] : 0.), (nonemptycell ? globals::gammaestimator[estimindex] : 0.)); } @@ -1852,12 +1796,11 @@ static void assign_initial_temperatures() /// according to the local energy density resulting from the 56Ni decay. /// The dilution factor is W=1 in LTE. - const double tstart = globals::time_step[0].mid; + const double tstart = globals::timesteps[0].mid; + + for (int nonempymgi = 0; nonempymgi < get_nonempty_npts_model(); nonempymgi++) { + const int mgi = get_mgi_of_nonemptymgi(nonempymgi); - for (int mgi = 0; mgi < get_npts_model(); mgi++) { - if (get_numassociatedcells(mgi) == 0) { - continue; - } double decayedenergy_per_mass = decay::get_endecay_per_ejectamass_t0_to_time_withexpansion(mgi, tstart); if constexpr (INITIAL_PACKETS_ON && USE_MODEL_INITIAL_ENERGY) { decayedenergy_per_mass += get_initenergyq(mgi); @@ -1945,13 +1888,12 @@ static void setup_nstart_ndo() { assert_always(npts_nonempty_assigned == get_nonempty_npts_model()); if (globals::rank_global == 0) { - std::ofstream fileout("modelgridrankassignments.out"); + auto fileout = std::ofstream("modelgridrankassignments.out"); assert_always(fileout.is_open()); fileout << "#rank nstart ndo ndo_nonempty\n"; for (int r = 0; r < nprocesses; r++) { fileout << r << " " << ranks_nstart[r] << " " << ranks_ndo[r] << " " << ranks_ndo_nonempty[r] << "\n"; } - fileout.close(); } } @@ -1983,7 +1925,7 @@ auto get_ndo_nonempty(const int rank) -> int { return ranks_ndo_nonempty[rank]; } -static void uniform_grid_setup() +static void setup_grid_cartesian_3d() /// Routine for doing a uniform cuboidal grid. { // vmax is per coordinate, but the simulation volume corners will @@ -1993,7 +1935,7 @@ static void uniform_grid_setup() assert_always(vmax_corner < CLIGHT); /// Set grid size for uniform xyz grid - if (get_model_type() == RHO_3D_READ) { + if (get_model_type() == GRID_CARTESIAN3D) { // if we used in a 3D ejecta model, the propagation grid must match the input grid exactly ncoordgrid[0] = ncoord_model[0]; ncoordgrid[1] = ncoord_model[1]; @@ -2023,7 +1965,7 @@ static void uniform_grid_setup() for (int n = 0; n < ngrid; n++) { for (int axis = 0; axis < 3; axis++) { assert_always(nxyz[axis] == get_cellcoordpointnum(n, axis)); - cell[n].pos_min[axis] = -globals::coordmax[axis] + (2 * nxyz[axis] * globals::coordmax[axis] / ncoordgrid[axis]); + cell[n].pos_min[axis] = -globals::rmax + (2 * nxyz[axis] * globals::rmax / ncoordgrid[axis]); // cell[n].xyz[axis] = nxyz[axis]; } @@ -2041,8 +1983,8 @@ static void uniform_grid_setup() } } -static void spherical1d_grid_setup() { - assert_always(get_model_type() == RHO_1D_READ); +static void setup_grid_spherical1d() { + assert_always(get_model_type() == GRID_SPHERICAL1D); coordlabel[0] = 'r'; coordlabel[1] = '_'; coordlabel[2] = '_'; @@ -2054,11 +1996,7 @@ static void spherical1d_grid_setup() { ngrid = ncoordgrid[0] * ncoordgrid[1] * ncoordgrid[2]; cell = static_cast(malloc(ngrid * sizeof(struct gridcell))); - globals::coordmax[0] = globals::rmax; - globals::coordmax[1] = 0.; - globals::coordmax[2] = 0.; - - // in this mode, cellindex and modelgridindex are the same thing + // direct mapping, cellindex and modelgridindex are the same for (int cellindex = 0; cellindex < get_npts_model(); cellindex++) { const int mgi = cellindex; // interchangeable in this mode const double v_inner = mgi > 0 ? vout_model[mgi - 1] : 0.; @@ -2069,22 +2007,52 @@ static void spherical1d_grid_setup() { } } +static void setup_grid_cylindrical_2d() { + const double vmax_corner = sqrt(2 * pow(globals::vmax, 2)); + printout("corner vmax %g [cm/s] (%.2fc)\n", vmax_corner, vmax_corner / CLIGHT); + assert_always(vmax_corner < CLIGHT); + + assert_always(get_model_type() == GRID_CYLINDRICAL2D); + coordlabel[0] = 'r'; + coordlabel[1] = 'z'; + coordlabel[2] = '_'; + + ncoordgrid[0] = ncoord_model[0]; + ncoordgrid[1] = ncoord_model[1]; + ncoordgrid[2] = ncoord_model[2]; + + ngrid = ncoordgrid[0] * ncoordgrid[1]; + cell = static_cast(malloc(ngrid * sizeof(struct gridcell))); + + // direct mapping, cellindex and modelgridindex are the same + for (int cellindex = 0; cellindex < get_npts_model(); cellindex++) { + const int mgi = cellindex; // interchangeable in this mode + set_cell_modelgridindex(cellindex, mgi); + + const int n_rcyl = get_cellcoordpointnum(cellindex, 0); + const int n_z = get_cellcoordpointnum(cellindex, 1); + + cell[cellindex].pos_min[0] = n_rcyl * globals::rmax / ncoord_model[0]; + cell[cellindex].pos_min[1] = globals::rmax * (-1 + n_z * 2. / ncoord_model[1]); + cell[cellindex].pos_min[2] = 0.; + } +} + void grid_init(int my_rank) /// Initialises the propagation grid cells and associates them with modelgrid cells { - for (int n = 0; n <= get_npts_model(); n++) { - modelgrid[n].initial_radial_pos_sum = 0; - } - /// The cells will be ordered by x then y, then z. Call a routine that /// sets up the initial positions and widths of the cells. char grid_type_name[256] = ""; - if (GRID_TYPE == GRID_UNIFORM) { - uniform_grid_setup(); + if (GRID_TYPE == GRID_CARTESIAN3D) { + setup_grid_cartesian_3d(); strcpy(grid_type_name, "uniform cuboidal"); } else if (GRID_TYPE == GRID_SPHERICAL1D) { - spherical1d_grid_setup(); + setup_grid_spherical1d(); strcpy(grid_type_name, "spherical"); + } else if (GRID_TYPE == GRID_CYLINDRICAL2D) { + setup_grid_cylindrical_2d(); + strcpy(grid_type_name, "cylindrical"); } else { printout("[fatal] grid_init: Error: Unknown grid type. Abort."); abort(); @@ -2102,19 +2070,26 @@ void grid_init(int my_rank) // Calculate the critical opacity at which opacity_case 3 switches from a // regime proportional to the density to a regime independent of the density // This is done by solving for tau_sobolev == 1 - // tau_sobolev = PI*QE*QE/(ME*C) * rho_crit_para * rho/nucmass(28, 56) * 3000e-8 * globals::time_step[m].mid; + // tau_sobolev = PI*QE*QE/(ME*C) * rho_crit_para * rho/nucmass(28, 56) * 3000e-8 * globals::timesteps[m].mid; globals::rho_crit = ME * CLIGHT * decay::nucmass(28, 56) / (PI * QE * QE * globals::rho_crit_para * 3000e-8 * globals::tmin); printout("grid_init: rho_crit = %g [g/cm3]\n", globals::rho_crit); - if (get_model_type() == RHO_1D_READ) { - map_1dmodeltogrid(); - } else if (get_model_type() == RHO_2D_READ) { - assert_always(GRID_TYPE == GRID_UNIFORM); - map_2dmodeltogrid(); - } else if (get_model_type() == RHO_3D_READ) { - assert_always(GRID_TYPE == GRID_UNIFORM); - map_3dmodeltogrid(); + if (get_model_type() == GRID_TYPE) { + if (get_model_type() == GRID_CARTESIAN3D) { + assert_always(GRID_TYPE == GRID_CARTESIAN3D); + assert_always(ncoord_model[0] == ncoordgrid[0]); + assert_always(ncoord_model[1] == ncoordgrid[1]); + assert_always(ncoord_model[2] == ncoordgrid[2]); + } + + map_modeltogrid_direct(); + } else if (get_model_type() == GRID_SPHERICAL1D) { + assert_always(GRID_TYPE == GRID_CARTESIAN3D); + map_1dmodelto3dgrid(); + } else if (get_model_type() == GRID_CYLINDRICAL2D) { + assert_always(GRID_TYPE == GRID_CARTESIAN3D); + map_2dmodelto3dgrid(); } else { printout("[fatal] grid_init: Error: Unknown density type. Abort."); abort(); @@ -2124,7 +2099,7 @@ void grid_init(int my_rank) calculate_kappagrey(); abundances_read(); - int const ndo_nonempty = grid::get_ndo_nonempty(my_rank); + const int ndo_nonempty = grid::get_ndo_nonempty(my_rank); radfield::init(my_rank, ndo_nonempty); nonthermal::init(my_rank, ndo_nonempty); @@ -2133,15 +2108,16 @@ void grid_init(int my_rank) if (globals::simulation_continued_from_saved) { /// For continuation of an existing simulation we read the temperatures /// at the end of the simulation and write them to the grid. - read_grid_restart_data(globals::itstep); + read_grid_restart_data(globals::timestep_initial); } else { assign_initial_temperatures(); } - // when mapping 1D spherical model onto cubic grid, scale up the + // when mapping 1D spherical or 2D cylindrical model onto cubic grid, scale up the // radioactive abundances to account for the missing masses in // the model cells that are not associated with any propagation cells - if (GRID_TYPE == GRID_UNIFORM && get_model_type() == RHO_1D_READ && globals::rank_in_node == 0) { + // Luke: TODO: it's probably better to adjust the density instead of the abundances + if (GRID_TYPE == GRID_CARTESIAN3D && get_model_type() == GRID_SPHERICAL1D && globals::rank_in_node == 0) { for (int nucindex = 0; nucindex < decay::get_num_nuclides(); nucindex++) { if (totmassradionuclide[nucindex] <= 0) { continue; @@ -2168,6 +2144,14 @@ void grid_init(int my_rank) } } } + + double mtot_mapped = 0.; + for (int mgi = 0; mgi < get_npts_model(); mgi++) { + mtot_mapped += get_rho_tmin(mgi) * get_modelcell_assocvolume_tmin(mgi); + } + printout("Total grid-mapped mass: %9.3e [Msun] (%.1f%% of input mass)\n", mtot_mapped / MSUN, + mtot_mapped / mtot_input * 100.); + #ifdef MPI_ON MPI_Barrier(MPI_COMM_WORLD); #endif @@ -2177,4 +2161,437 @@ auto get_totmassradionuclide(const int z, const int a) -> double { return totmassradionuclide[decay::get_nucindex(z, a)]; } +static auto get_poscoordpointnum(double pos, double time, int axis) -> int { + // pos must be position in grid coordinate system, not necessarily xyz + + if constexpr (GRID_TYPE == GRID_CARTESIAN3D) { + return static_cast((pos / time + globals::vmax) / 2 / globals::vmax * ncoordgrid[axis]); + } else if constexpr (GRID_TYPE == GRID_CYLINDRICAL2D) { + if (axis == 0) { + return static_cast(pos / time / globals::vmax * ncoordgrid[axis]); + } + if (axis == 1) { + return static_cast((pos / time + globals::vmax) / 2 / globals::vmax * ncoordgrid[axis]); + } + assert_always(false); + + } else if constexpr (GRID_TYPE == GRID_SPHERICAL1D) { + for (int n_r = 0; n_r < ncoordgrid[0]; n_r++) { + if ((pos >= grid::get_cellcoordmin(n_r, 0)) && (pos < grid::get_cellcoordmax(n_r, 0))) { + return n_r; + } + } + assert_always(false); + } else { + assert_always(false); + } +} + +auto get_cellindex_from_pos(std::span pos, double time) -> int +/// identify the cell index from an (x,y,z) position and a time. +{ + double posgridcoords[3] = {NAN, NAN, NAN}; + get_gridcoords_from_xyz(pos, posgridcoords); + int cellindex = 0; + for (int d = 0; d < get_ngriddimensions(); d++) { + cellindex += get_coordcellindexincrement(d) * get_poscoordpointnum(posgridcoords[d], time, d); + } + + // do a check that the position is within the cell + const double trat = time / globals::tmin; + for (int n = 0; n < grid::get_ngriddimensions(); n++) { + assert_always(posgridcoords[n] >= grid::get_cellcoordmin(cellindex, n) * trat); + assert_always(posgridcoords[n] <= grid::get_cellcoordmax(cellindex, n) * trat); + } + return cellindex; +} + +[[nodiscard]] [[gnu::pure]] static constexpr auto expanding_shell_intersection( + std::span pos, std::span dir, const double speed, const double shellradiuststart, + const bool isinnerboundary, const double tstart) -> double +// find the closest forward distance to the intersection of a ray with an expanding spherical shell (pos and dir are +// 3-vectors) or expanding circle (2D vectors) +// returns -1 if there are no forward intersections (or if the intersection +// is tangential to the shell) +{ + assert_always(shellradiuststart > 0); + + // quadratic equation for intersection of ray with sphere + // a*d^2 + b*d + c = 0 + const double a = dot(dir, dir) - pow(shellradiuststart / tstart / speed, 2); + const double b = 2 * (dot(dir, pos) - pow(shellradiuststart, 2) / tstart / speed); + const double c = dot(pos, pos) - pow(shellradiuststart, 2); + + const double discriminant = pow(b, 2) - 4 * a * c; + + if (discriminant < 0) { + // no intersection + assert_always(isinnerboundary); + assert_always(shellradiuststart < vec_len(pos)); + return -1; + } + + if (discriminant > 0) { + // two intersections + double dist1 = (-b + sqrt(discriminant)) / 2 / a; + double dist2 = (-b - sqrt(discriminant)) / 2 / a; + + double posfinal1[3] = {0}; + double posfinal2[3] = {0}; + + for (size_t d = 0; d < pos.size(); d++) { + posfinal1[d] = pos[d] + dist1 * dir[d]; + posfinal2[d] = pos[d] + dist2 * dir[d]; + } + + const double v_rad_shell = shellradiuststart / tstart; + const double v_rad_final1 = dot(dir, posfinal1) * speed / vec_len(posfinal1); + const double v_rad_final2 = dot(dir, posfinal2) * speed / vec_len(posfinal2); + + // invalidate any solutions that require entering the boundary from the wrong radial direction + if (isinnerboundary) { + // if the packet's radial velocity at intersection is greater than the inner shell's radial velocity, + // then it is catching up from below the inner shell and should pass through it + if (v_rad_final1 > v_rad_shell) { + dist1 = -1; + } + if (v_rad_final2 > v_rad_shell) { + dist2 = -1; + } + } else { + // if the packet's radial velocity at intersection is less than the outer shell's radial velocity, + // then it is coming from above the outer shell and should pass through it + if (v_rad_final1 < v_rad_shell) { + dist1 = -1; + } + if (v_rad_final2 < v_rad_shell) { + dist2 = -1; + } + } + + if (dist1 >= 0) { + const double shellradiusfinal1 = shellradiuststart / tstart * (tstart + dist1 / speed); + assert_testmodeonly(fabs(vec_len(posfinal1) / shellradiusfinal1 - 1.) < 1e-3); + } + + if (dist2 >= 0) { + const double shellradiusfinal2 = shellradiuststart / tstart * (tstart + dist2 / speed); + assert_testmodeonly(fabs(vec_len(posfinal2) / shellradiusfinal2 - 1.) < 1e-3); + } + + // negative d means in the reverse direction along the ray + // ignore negative d values, and if two are positive then return the smaller one + if (dist1 < 0 && dist2 < 0) { + return -1; + } + if (dist2 < 0) { + return dist1; + } + if (dist1 < 0) { + return dist2; + } + return fmin(dist1, dist2); + + } // exactly one intersection + + // one intersection + // ignore this and don't change which cell the packet is in + assert_always(shellradiuststart <= vec_len(pos)); + return -1.; +} + +static auto get_coordboundary_distances_cylindrical2d(std::span pkt_pos, + std::span pkt_dir, + std::span pktposgridcoord, + std::span pktvelgridcoord, int cellindex, + const double tstart, std::span cellcoordmax, + std::span d_coordminboundary, + std::span d_coordmaxboundary) -> void { + // to get the cylindrical intersection, get the spherical intersection with Z components set to zero, and the + // propagation speed set to the xy component of the 3-velocity + + const double posnoz[2] = {pkt_pos[0], pkt_pos[1]}; + + const double dirxylen = std::sqrt((pkt_dir[0] * pkt_dir[0]) + (pkt_dir[1] * pkt_dir[1])); + const double xyspeed = dirxylen * CLIGHT_PROP; // r_cyl component of velocity + + // make a normalised direction vector in the xy plane + const double dirnoz[2] = {pkt_dir[0] / dirxylen, pkt_dir[1] / dirxylen}; + + const double r_inner = grid::get_cellcoordmin(cellindex, 0) * tstart / globals::tmin; + d_coordminboundary[0] = -1; + // don't try to calculate the intersection if the inner radius is zero + if (r_inner > 0) { + const double d_rcyl_coordminboundary = expanding_shell_intersection(posnoz, dirnoz, xyspeed, r_inner, true, tstart); + if (d_rcyl_coordminboundary >= 0) { + const double d_z_coordminboundary = d_rcyl_coordminboundary / xyspeed * pkt_dir[2] * CLIGHT_PROP; + d_coordminboundary[0] = + std::sqrt(d_rcyl_coordminboundary * d_rcyl_coordminboundary + d_z_coordminboundary * d_z_coordminboundary); + } + } + + const double r_outer = cellcoordmax[0] * tstart / globals::tmin; + const double d_rcyl_coordmaxboundary = expanding_shell_intersection(posnoz, dirnoz, xyspeed, r_outer, false, tstart); + d_coordmaxboundary[0] = -1; + if (d_rcyl_coordmaxboundary >= 0) { + const double d_z_coordmaxboundary = d_rcyl_coordmaxboundary / xyspeed * pkt_dir[2] * CLIGHT_PROP; + d_coordmaxboundary[0] = + std::sqrt(d_rcyl_coordmaxboundary * d_rcyl_coordmaxboundary + d_z_coordmaxboundary * d_z_coordmaxboundary); + } + + // z boundaries are the same as Cartesian + const double t_zcoordminboundary = + ((pktposgridcoord[1] - (pktvelgridcoord[1] * tstart)) / + ((grid::get_cellcoordmin(cellindex, 1)) - (pktvelgridcoord[1] * globals::tmin)) * globals::tmin) - + tstart; + d_coordminboundary[1] = CLIGHT_PROP * t_zcoordminboundary; + + const double t_zcoordmaxboundary = ((pktposgridcoord[1] - (pktvelgridcoord[1] * tstart)) / + ((cellcoordmax[1]) - (pktvelgridcoord[1] * globals::tmin)) * globals::tmin) - + tstart; + d_coordmaxboundary[1] = CLIGHT_PROP * t_zcoordmaxboundary; +} + +[[nodiscard]] auto boundary_distance(std::span dir, std::span pos, + const double tstart, int cellindex, int *snext, enum cell_boundary *pkt_last_cross) + -> double +/// Basic routine to compute distance to a cell boundary. +{ + if constexpr (FORCE_SPHERICAL_ESCAPE_SURFACE) { + if (get_cell_r_inner(cellindex) > globals::vmax * globals::tmin) { + *snext = -99; + return 0.; + } + } + + auto last_cross = *pkt_last_cross; + // d is used to loop over the coordinate indicies 0,1,2 for x,y,z + + // the following four vectors are in grid coordinates, so either x,y,z or r + const int ndim = grid::get_ngriddimensions(); + assert_testmodeonly(ndim <= 3); + double pktposgridcoord[3] = {0}; // pos converted from xyz to propagation grid coordinates + double cellcoordmax[3] = {0}; + double pktvelgridcoord[3] = {0}; // dir * CLIGHT_PROP converted from xyz to grid coordinates + + get_gridcoords_from_xyz(pos, pktposgridcoord); + + for (int d = 0; d < ndim; d++) { + cellcoordmax[d] = grid::get_cellcoordmax(cellindex, d); + } + if constexpr (GRID_TYPE == GRID_CARTESIAN3D) { + // keep xyz Cartesian coordinates + for (int d = 0; d < ndim; d++) { + pktvelgridcoord[d] = dir[d] * CLIGHT_PROP; + } + } else if constexpr (GRID_TYPE == GRID_CYLINDRICAL2D) { + // xy plane radial velocity + pktvelgridcoord[0] = (pos[0] * dir[0] + pos[1] * dir[1]) / pktposgridcoord[0] * CLIGHT_PROP; + + // second cylindrical coordinate is z + pktvelgridcoord[1] = dir[2] * CLIGHT_PROP; + + } else if constexpr (GRID_TYPE == GRID_SPHERICAL1D) { + // the only coordinate is radius from the origin + pktvelgridcoord[0] = dot(pos, dir) / pktposgridcoord[0] * CLIGHT_PROP; // radial velocity + } else { + assert_always(false); + } + + enum cell_boundary const negdirections[3] = {COORD0_MIN, COORD1_MIN, + COORD2_MIN}; // 'X' might actually be radial coordinate + enum cell_boundary const posdirections[3] = {COORD0_MAX, COORD1_MAX, COORD2_MAX}; + + // printout("checking inside cell boundary\n"); + for (int d = 0; d < ndim; d++) { + // flip is either zero or one to indicate +ve and -ve boundaries along the selected axis + for (int flip = 0; flip < 2; flip++) { + enum cell_boundary const direction = flip != 0 ? posdirections[d] : negdirections[d]; + enum cell_boundary const invdirection = flip == 0 ? posdirections[d] : negdirections[d]; + const int cellindexstride = + flip != 0 ? -grid::get_coordcellindexincrement(d) : grid::get_coordcellindexincrement(d); + + bool isoutside_thisside = false; + double delta = 0.; + if (flip != 0) { + // packet pos below min + const double boundaryposmin = grid::get_cellcoordmin(cellindex, d) / globals::tmin * tstart; + delta = pktposgridcoord[d] - boundaryposmin; + isoutside_thisside = pktposgridcoord[d] < (boundaryposmin - 10.); // 10 cm accuracy tolerance + } else { + // packet pos above max + const double boundaryposmax = cellcoordmax[d] / globals::tmin * tstart; + delta = pktposgridcoord[d] - boundaryposmax; + isoutside_thisside = pktposgridcoord[d] > (boundaryposmax + 10.); + } + + if (isoutside_thisside && (last_cross != direction)) { + // for (int d2 = 0; d2 < ndim; d2++) + const int d2 = d; + { + printout( + "[warning] packet outside coord %d %c%c boundary of cell %d. vel %g initpos %g " + "cellcoordmin %g, cellcoordmax %g\n", + d, flip != 0 ? '-' : '+', grid::coordlabel[d], cellindex, pktvelgridcoord[d2], pktposgridcoord[d2], + grid::get_cellcoordmin(cellindex, d2) / globals::tmin * tstart, + cellcoordmax[d2] / globals::tmin * tstart); + } + printout("globals::tmin %g tstart %g tstart/globals::tmin %g\n", globals::tmin, tstart, tstart / globals::tmin); + printout("[warning] delta %g\n", delta); + + printout("[warning] dir [%g, %g, %g]\n", dir[0], dir[1], dir[2]); + if ((pktvelgridcoord[d] - (pktposgridcoord[d] / tstart)) > 0) { + if ((grid::get_cellcoordpointnum(cellindex, d) == (grid::ncoordgrid[d] - 1) && cellindexstride > 0) || + (grid::get_cellcoordpointnum(cellindex, d) == 0 && cellindexstride < 0)) { + printout("escaping packet\n"); + *snext = -99; + return 0; + } + *snext = cellindex + cellindexstride; + *pkt_last_cross = invdirection; + printout("[warning] swapping packet cellindex from %d to %d and setting last_cross to %d\n", cellindex, + *snext, *pkt_last_cross); + return 0; + } + printout("pretending last_cross is %d\n", direction); + last_cross = direction; + } + } + } + + // printout("pkt_ptr->number %d\n", pkt_ptr->number); + // printout("delta1x %g delta2x %g\n", (initpos[0] * globals::tmin/tstart)-grid::get_cellcoordmin(cellindex, 0), + // cellcoordmax[0] - (initpos[0] * globals::tmin/tstart)); printout("delta1y %g delta2y %g\n", (initpos[1] * + // globals::tmin/tstart)-grid::get_cellcoordmin(cellindex, 1), cellcoordmax[1] - (initpos[1] * + // globals::tmin/tstart)); printout("delta1z %g delta2z %g\n", (initpos[2] * + // globals::tmin/tstart)-grid::get_cellcoordmin(cellindex, 2), cellcoordmax[2] - (initpos[2] * + // globals::tmin/tstart)); printout("dir [%g, %g, %g]\n", dir[0],dir[1],dir[2]); + + double d_coordmaxboundary[3] = {-1}; // distance to reach the cell's upper boundary on each coordinate + double d_coordminboundary[3] = {-1}; // distance to reach the cell's lower boundary on each coordinate + if constexpr (GRID_TYPE == GRID_SPHERICAL1D) { + last_cross = BOUNDARY_NONE; // handle this separately by setting d_inner and d_outer negative for invalid direction + const double speed = vec_len(dir) * CLIGHT_PROP; // just in case dir is not normalised + + const double r_inner = grid::get_cellcoordmin(cellindex, 0) * tstart / globals::tmin; + d_coordminboundary[0] = (r_inner > 0.) ? expanding_shell_intersection(pos, dir, speed, r_inner, true, tstart) : -1.; + + const double r_outer = cellcoordmax[0] * tstart / globals::tmin; + d_coordmaxboundary[0] = expanding_shell_intersection(pos, dir, speed, r_outer, false, tstart); + + } else if constexpr (GRID_TYPE == GRID_CYLINDRICAL2D) { + // coordinate 0 is radius in x-y plane, coord 1 is z + if (last_cross == COORD0_MIN || last_cross == COORD0_MAX) { + last_cross = + BOUNDARY_NONE; // handle this separately by setting d_inner and d_outer negative for invalid direction + } + + get_coordboundary_distances_cylindrical2d(pos, dir, pktposgridcoord, pktvelgridcoord, cellindex, tstart, + cellcoordmax, d_coordminboundary, d_coordmaxboundary); + + } else if constexpr (GRID_TYPE == GRID_CARTESIAN3D) { + // There are six possible boundary crossings. Each of the three + // cartesian coordinates may be taken in turn. For x, the packet + // trajectory is + // x = x0 + (dir.x) * c * (t - tstart) + // the boundries follow + // x+/- = x+/-(tmin) * (t/tmin) + // so the crossing occurs when + // t = (x0 - (dir.x)*c*tstart)/(x+/-(tmin)/tmin - (dir.x)c) + + // Modified so that it also returns the distance to the closest cell + // boundary, regardless of direction. + + for (int d = 0; d < 3; d++) { + const double t_coordminboundary = + ((pktposgridcoord[d] - (pktvelgridcoord[d] * tstart)) / + (grid::get_cellcoordmin(cellindex, d) - (pktvelgridcoord[d] * globals::tmin)) * globals::tmin) - + tstart; + d_coordminboundary[d] = CLIGHT_PROP * t_coordminboundary; + + const double t_coordmaxboundary = ((pktposgridcoord[d] - (pktvelgridcoord[d] * tstart)) / + (cellcoordmax[d] - (pktvelgridcoord[d] * globals::tmin)) * globals::tmin) - + tstart; + + d_coordmaxboundary[d] = CLIGHT_PROP * t_coordmaxboundary; + } + } else { + assert_always(false); + } + + // We now need to identify the shortest +ve distance - that's the one we want. + enum cell_boundary choice = BOUNDARY_NONE; + double distance = std::numeric_limits::max(); + for (int d = 0; d < ndim; d++) { + // upper d coordinate of the current cell + if ((d_coordmaxboundary[d] > 0) && (d_coordmaxboundary[d] < distance) && (last_cross != negdirections[d])) { + choice = posdirections[d]; + distance = d_coordmaxboundary[d]; + if (grid::get_cellcoordpointnum(cellindex, d) == (grid::ncoordgrid[d] - 1)) { + *snext = -99; + } else { + *pkt_last_cross = choice; + *snext = cellindex + grid::get_coordcellindexincrement(d); + } + } + + // lower d coordinate of the current cell + if ((d_coordminboundary[d] > 0) && (d_coordminboundary[d] < distance) && (last_cross != posdirections[d])) { + choice = negdirections[d]; + distance = d_coordminboundary[d]; + if (grid::get_cellcoordpointnum(cellindex, d) == 0) { + *snext = -99; + } else { + *pkt_last_cross = choice; + *snext = cellindex - grid::get_coordcellindexincrement(d); + } + } + } + + if (choice == BOUNDARY_NONE) { + printout("Something wrong in boundary crossing - didn't find anything.\n"); + printout("packet cell %d\n", cellindex); + printout("choice %d\n", choice); + printout("globals::tmin %g tstart %g\n", globals::tmin, tstart); + printout("last_cross %d\n", last_cross); + for (int d2 = 0; d2 < 3; d2++) { + printout("coord %d: initpos %g dir %g\n", d2, pos[d2], dir[d2]); + } + printout("|initpos| %g |dir| %g |pos.dir| %g\n", vec_len(pos), vec_len(dir), dot(pos, dir)); + for (int d2 = 0; d2 < ndim; d2++) { + printout("coord %d: dist_posmax %g dist_posmin %g \n", d2, d_coordmaxboundary[d2], d_coordminboundary[d2]); + printout("coord %d: cellcoordmin %g cellcoordmax %g\n", d2, + grid::get_cellcoordmin(cellindex, d2) * tstart / globals::tmin, + cellcoordmax[d2] * tstart / globals::tmin); + } + printout("tstart %g\n", tstart); + + assert_always(false); + } + + return distance; +} + +void change_cell(struct packet *pkt_ptr, int snext) +/// Routine to take a packet across a boundary. +{ + // const int cellindex = pkt_ptr->where; + // printout("[debug] cellnumber %d nne %g\n", cellindex, grid::get_nne(grid::get_cell_modelgridindex(cellindex))); + // printout("[debug] snext %d\n", snext); + + if (snext == -99) { + // Then the packet is exiting the grid. We need to record + // where and at what time it leaves the grid. + pkt_ptr->escape_type = pkt_ptr->type; + pkt_ptr->escape_time = pkt_ptr->prop_time; + pkt_ptr->type = TYPE_ESCAPE; + globals::nesc++; + } else { + // Just need to update "where". + pkt_ptr->where = snext; + + stats::increment(stats::COUNTER_CELLCROSSINGS); + } +} + } // namespace grid diff --git a/grid.h b/grid.h index 628527b3d..80d0834b2 100644 --- a/grid.h +++ b/grid.h @@ -2,9 +2,12 @@ #define GRIDINIT_H #include +#include #include "artisoptions.h" #include "constants.h" +#include "packet.h" +#include "vectors.h" namespace grid { @@ -21,13 +24,6 @@ struct gridcell { int modelgridindex; }; -enum model_types { - RHO_UNIFORM = 1, // Constant density. NOT IN USE - RHO_1D_READ = 2, // Read model 1D - RHO_2D_READ = 4, // Read model 2D - RHO_3D_READ = 3, // Read model 3D -}; - struct modelgrid_t { float Te = -1.; float TR = -1.; @@ -62,7 +58,17 @@ struct modelgrid_t { uint_fast8_t thick = 0; }; -constexpr int get_ngriddimensions(void) { return (GRID_TYPE == GRID_SPHERICAL1D) ? 1 : 3; } +constexpr int get_ngriddimensions(void) { + switch (GRID_TYPE) { + case GRID_SPHERICAL1D: + return 1; + case GRID_CYLINDRICAL2D: + return 2; + case GRID_CARTESIAN3D: + return 3; + } + assert_always(false); +} extern struct modelgrid_t *modelgrid; @@ -72,7 +78,7 @@ extern char coordlabel[3]; int get_elements_uppermost_ion(int modelgridindex, int element); void set_elements_uppermost_ion(int modelgridindex, int element, int newvalue); -double wid_init(int cellindex); +double wid_init(int cellindex, int axis); double get_modelcell_assocvolume_tmin(int modelgridindex); double get_gridcell_volume_tmin(int cellindex); double get_cellcoordmax(int cellindex, int axis); @@ -96,12 +102,12 @@ float get_W(int modelgridindex); void set_nne(int modelgridindex, float nne); void set_nnetot(int modelgridindex, float x); void set_kappagrey(int modelgridindex, float kappagrey); +void set_rho(int modelgridindex, float x); void set_Te(int modelgridindex, float Te); void set_TR(int modelgridindex, float TR); void set_TJ(int modelgridindex, float TJ); void set_W(int modelgridindex, float W); void grid_init(int my_rank); -double get_cellradialpos(int cellindex); float get_modelinitradioabund(int modelgridindex, int nucindex); float get_stable_initabund(int mgi, int element); float get_element_meanweight(int mgi, int element); @@ -110,12 +116,13 @@ double get_electronfrac(int modelgridindex); int get_numassociatedcells(int modelgridindex); int get_modelcell_nonemptymgi(int mgi); int get_mgi_of_nonemptymgi(int nonemptymgi); -enum model_types get_model_type(); -void set_model_type(enum model_types model_type_value); +enum gridtypes get_model_type(); +void set_model_type(enum gridtypes model_type_value); int get_npts_model(); int get_nonempty_npts_model(); double get_t_model(); int get_cell_modelgridindex(int cellindex); +int get_cellindex_from_pos(std::span pos, double time); void read_ejecta_model(); void write_grid_restart_data(int timestep); int get_maxndo(); @@ -123,6 +130,9 @@ int get_nstart(int rank); int get_ndo(int rank); int get_ndo_nonempty(int rank); double get_totmassradionuclide(int z, int a); +double boundary_distance(std::span dir, std::span pos, double tstart, int cellindex, + int *snext, enum cell_boundary *pkt_last_cross); +void change_cell(struct packet *pkt_ptr, int snext); static inline float get_elem_abundance(int modelgridindex, int element) // mass fraction of an element (all isotopes combined) @@ -130,6 +140,22 @@ static inline float get_elem_abundance(int modelgridindex, int element) return modelgrid[modelgridindex].composition[element].abundance; } +constexpr auto get_gridcoords_from_xyz(std::span pos_xyz, std::span posgridcoord) -> void { + if constexpr (GRID_TYPE == GRID_CARTESIAN3D) { + posgridcoord[0] = pos_xyz[0]; + posgridcoord[1] = pos_xyz[1]; + posgridcoord[2] = pos_xyz[2]; + } else if constexpr (GRID_TYPE == GRID_CYLINDRICAL2D) { + posgridcoord[0] = std::sqrt(std::pow(pos_xyz[0], 2) + std::pow(pos_xyz[1], 2)); + posgridcoord[1] = pos_xyz[2]; + posgridcoord[2] = 0.; + } else if constexpr (GRID_TYPE == GRID_SPHERICAL1D) { + posgridcoord[0] = vec_len(pos_xyz); + posgridcoord[1] = 0.; + posgridcoord[2] = 0.; + } +} + } // namespace grid #endif // GRIDINIT_H diff --git a/input.cc b/input.cc index fc51b77d9..fcaacbb9b 100644 --- a/input.cc +++ b/input.cc @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -20,6 +21,7 @@ #include "grid.h" #include "kpkt.h" #include "nltepop.h" +#include "ratecoeff.h" #include "rpkt.h" #include "sn3d.h" #include "vpkt.h" @@ -34,15 +36,15 @@ struct transitions { struct transitiontable_entry { int lower; int upper; - double A; - double coll_str; + float A; + float coll_str; bool forbidden; }; /// only used temporarily during input -const std::array inputlinecomments = { +constexpr std::array inputlinecomments = { " 0: pre_zseed: specific random number seed if > 0 or random if negative", - " 1: globals::ntstep: number of timesteps", - " 2: itstep ftstep: timestep number range start (inclusive) and stop (not inclusive)", + " 1: ntimesteps: number of timesteps", + " 2: timestep_start timestep_finish: timestep number range start (inclusive) and stop (not inclusive)", " 3: tmin_days tmax_days: start and end times [day]", " 4: UNUSED nusyn_min_mev nusyn_max_mev: lowest and highest frequency to synthesise [MeV]", " 5: UNUSED nsyn_time: number of times for synthesis", @@ -51,7 +53,7 @@ const std::array inputlinecomments = { " 8: UNUSED compute r-light curve (1: no estimators, 2: thin cells, 3: thick cells, 4: gamma-ray heating)", " 9: UNUSED n_out_it: number of iterations", "10: UNUSED: change speed of light by some factor. Change constants.h CLIGHT_PROP instead", - "11: use grey opacity for gammas?", + "11: gamma_kappagrey: if >0: use grey opacity for gammas, if <0: use detailed opacity", "12: syn_dir: x, y, and z components of unit vector (will be normalised after input or randomised if zero length)", "13: opacity_case: opacity choice", "14: rho_crit_para: free parameter for calculation of rho_crit", @@ -68,7 +70,7 @@ const std::array inputlinecomments = { "23: kpktdiffusion_timescale n_kpktdiffusion_timesteps: kpkts diffuse x of a time step's length for the first y " "time steps"}; -static void read_phixs_data_table(FILE *phixsdata, const int nphixspoints_inputtable, const int element, +static void read_phixs_data_table(std::fstream &phixsfile, const int nphixspoints_inputtable, const int element, const int lowerion, const int lowerlevel, const int upperion, int upperlevel_in, const double phixs_threshold_ev, size_t *mem_usage_phixs) { if (upperlevel_in >= 0) // file gives photoionisation to a single target state only @@ -94,7 +96,7 @@ static void read_phixs_data_table(FILE *phixsdata, const int nphixspoints_inputt } else // upperlevel < 0, indicating that a table of upper levels and their probabilities will follow { int in_nphixstargets = 0; - assert_always(fscanf(phixsdata, "%d\n", &in_nphixstargets) == 1); + assert_always(phixsfile >> in_nphixstargets); assert_always(in_nphixstargets >= 0); // read in a table of target states and probabilities and store them if (!single_level_top_ion || upperion < get_nions(element) - 1) // in case the top ion has nlevelsmax = 1 @@ -109,7 +111,7 @@ static void read_phixs_data_table(FILE *phixsdata, const int nphixspoints_inputt double probability_sum = 0.; for (int i = 0; i < in_nphixstargets; i++) { double phixstargetprobability = NAN; - assert_always(fscanf(phixsdata, "%d %lg\n", &upperlevel_in, &phixstargetprobability) == 2); + assert_always(phixsfile >> upperlevel_in >> phixstargetprobability); const int upperlevel = upperlevel_in - groundstate_index_in; assert_always(upperlevel >= 0); assert_always(phixstargetprobability > 0); @@ -132,7 +134,7 @@ static void read_phixs_data_table(FILE *phixsdata, const int nphixspoints_inputt for (int i = 0; i < in_nphixstargets; i++) { double phixstargetprobability = NAN; - assert_always(fscanf(phixsdata, "%d %lg\n", &upperlevel_in, &phixstargetprobability) == 2); + assert_always(phixsfile >> upperlevel_in >> phixstargetprobability); } // send it to the ground state of the top ion @@ -177,7 +179,7 @@ static void read_phixs_data_table(FILE *phixsdata, const int nphixspoints_inputt assert_always(get_nphixstargets(element, lowerion, lowerlevel) == 1); assert_always(get_phixsupperlevel(element, lowerion, lowerlevel, 0) == 0); - double const nu_edge = (epsilon(element, upperion, 0) - epsilon(element, lowerion, lowerlevel)) / H; + const double nu_edge = (epsilon(element, upperion, 0) - epsilon(element, lowerion, lowerlevel)) / H; auto *nutable = static_cast(calloc(nphixspoints_inputtable, sizeof(double))); assert_always(nutable != nullptr); @@ -187,7 +189,7 @@ static void read_phixs_data_table(FILE *phixsdata, const int nphixspoints_inputt for (int i = 0; i < nphixspoints_inputtable; i++) { double energy = -1.; double phixs = -1.; - assert_always(fscanf(phixsdata, "%lg %lg", &energy, &phixs) == 2); + assert_always(phixsfile >> energy >> phixs); nutable[i] = nu_edge + (energy * 13.6 * EV) / H; /// the photoionisation cross-sections in the database are given in Mbarn=1e6 * 1e-28m^2 /// to convert to cgs units multiply by 1e-18 @@ -218,7 +220,7 @@ static void read_phixs_data_table(FILE *phixsdata, const int nphixspoints_inputt } else { for (int i = 0; i < globals::NPHIXSPOINTS; i++) { float phixs = NAN; - assert_always(fscanf(phixsdata, "%g\n", &phixs) == 1); + assert_always(phixsfile >> phixs); assert_always(phixs >= 0); /// the photoionisation cross-sections in the database are given in Mbarn = 1e6 * 1e-28m^2 @@ -241,7 +243,7 @@ static void read_phixs_data(const int phixs_file_version) { printout("readin phixs data from %s\n", phixsdata_filenames[phixs_file_version]); - FILE *phixsdata = fopen_required(phixsdata_filenames[phixs_file_version], "r"); + auto phixsfile = fstream_required(phixsdata_filenames[phixs_file_version], std::ios::in); if (phixs_file_version == 1 && phixs_file_version_exists[2]) { printout( @@ -257,9 +259,9 @@ static void read_phixs_data(const int phixs_file_version) { printout("using NPHIXSPOINTS = %d and NPHIXSNUINCREMENT = %lg set in input.cc\n", globals::NPHIXSPOINTS, globals::NPHIXSNUINCREMENT); } else { - assert_always(fscanf(phixsdata, "%d\n", &globals::NPHIXSPOINTS) == 1); + assert_always(phixsfile >> globals::NPHIXSPOINTS); assert_always(globals::NPHIXSPOINTS > 0); - assert_always(fscanf(phixsdata, "%lg\n", &globals::NPHIXSNUINCREMENT) == 1); + assert_always(phixsfile >> globals::NPHIXSNUINCREMENT); assert_always(globals::NPHIXSNUINCREMENT > 0.); last_phixs_nuovernuedge = (1.0 + globals::NPHIXSNUINCREMENT * (globals::NPHIXSPOINTS - 1)); } @@ -271,20 +273,19 @@ static void read_phixs_data(const int phixs_file_version) { int lowerlevel_in = -1; double phixs_threshold_ev = -1; while (true) { - int readstatus = -1; int nphixspoints_inputtable = 0; + std::string phixsline; + if (!get_noncommentline(phixsfile, phixsline)) { + break; + } if (phixs_file_version == 1) { - readstatus = fscanf(phixsdata, "%d %d %d %d %d %d\n", &Z, &upperionstage, &upperlevel_in, &lowerionstage, - &lowerlevel_in, &nphixspoints_inputtable); + assert_always(std::istringstream(phixsline) >> Z >> upperionstage >> upperlevel_in >> lowerionstage >> + lowerlevel_in >> nphixspoints_inputtable); } else { - readstatus = fscanf(phixsdata, "%d %d %d %d %d %lg\n", &Z, &upperionstage, &upperlevel_in, &lowerionstage, - &lowerlevel_in, &phixs_threshold_ev); + assert_always(std::istringstream(phixsline) >> Z >> upperionstage >> upperlevel_in >> lowerionstage >> + lowerlevel_in >> phixs_threshold_ev); nphixspoints_inputtable = globals::NPHIXSPOINTS; } - if (readstatus == EOF) { - break; - } - assert_always(readstatus == 6); assert_always(Z > 0); assert_always(upperionstage >= 2); assert_always(lowerionstage >= 1); @@ -296,7 +297,7 @@ static void read_phixs_data(const int phixs_file_version) { /// store only photoionization crosssections for elements that are part of the current model atom skip_this_phixs_table = true; // will be set to false for good data - if (element >= 0) { + if (element >= 0 && get_nions(element) > 0) { /// translate readin ionstages to ion indices const int upperion = upperionstage - get_ionstage(element, 0); @@ -306,7 +307,7 @@ static void read_phixs_data(const int phixs_file_version) { assert_always(lowerlevel >= 0); /// store only photoionization crosssections for ions that are part of the current model atom if (lowerion >= 0 && upperion < get_nions(element) && lowerlevel < get_nlevels(element, lowerion)) { - read_phixs_data_table(phixsdata, nphixspoints_inputtable, element, lowerion, lowerlevel, upperion, + read_phixs_data_table(phixsfile, nphixspoints_inputtable, element, lowerion, lowerlevel, upperion, upperlevel_in, phixs_threshold_ev, &mem_usage_phixs); skip_this_phixs_table = false; @@ -319,10 +320,10 @@ static void read_phixs_data(const int phixs_file_version) { if (upperlevel_in < 0) // a table of target states and probabilities will follow, so read past those lines { int nphixstargets = 0; - assert_always(fscanf(phixsdata, "%d\n", &nphixstargets) == 1); + assert_always(phixsfile >> nphixstargets); for (int i = 0; i < nphixstargets; i++) { double phixstargetprobability = NAN; - assert_always(fscanf(phixsdata, "%d %lg\n", &upperlevel_in, &phixstargetprobability) == 2); + assert_always(phixsfile >> upperlevel_in >> phixstargetprobability); } } for (int i = 0; i < nphixspoints_inputtable; i++) // skip through cross section list @@ -330,20 +331,18 @@ static void read_phixs_data(const int phixs_file_version) { float phixs = 0; if (phixs_file_version == 1) { double energy = 0; - assert_always(fscanf(phixsdata, "%lg %g\n", &energy, &phixs) == 2); + assert_always(phixsfile >> energy >> phixs); } else { - assert_always(fscanf(phixsdata, "%g\n", &phixs) == 1); + assert_always(phixsfile >> phixs); } } } } - fclose(phixsdata); - printout("[info] mem_usage: photoionisation tables occupy %.3f MB\n", mem_usage_phixs / 1024. / 1024.); } -static void read_ion_levels(FILE *adata, const int element, const int ion, const int nions, const int nlevels, +static void read_ion_levels(std::fstream &adata, const int element, const int ion, const int nions, const int nlevels, int nlevelsmax, const double energyoffset, const double ionpot, struct transitions *transitions) { const int nlevels_used = std::min(nlevels, nlevelsmax); @@ -357,8 +356,9 @@ static void read_ion_levels(FILE *adata, const int element, const int ion, const double levelenergy = NAN; double statweight = NAN; int ntransitions = 0; - assert_always(fscanf(adata, "%d %lg %lg %d%*[^\n]\n", &levelindex_in, &levelenergy, &statweight, &ntransitions) == - 4); + std::string line; + assert_always(get_noncommentline(adata, line)); + assert_always(std::istringstream(line) >> levelindex_in >> levelenergy >> statweight >> ntransitions); assert_always(levelindex_in == level + groundstate_index_in); if (level < nlevelsmax) { @@ -402,10 +402,13 @@ static void read_ion_levels(FILE *adata, const int element, const int ion, const } } -static void read_ion_transitions(std::istream &ftransitiondata, const int tottransitions_in_file, int *tottransitions, +static void read_ion_transitions(std::fstream &ftransitiondata, const int tottransitions_in_file, int *tottransitions, std::vector &transitiontable, const int nlevels_requiretransitions, const int nlevels_requiretransitions_upperlevels) { + transitiontable.reserve(*tottransitions); + transitiontable.clear(); + std::string line; if (*tottransitions == 0) { @@ -422,26 +425,25 @@ static void read_ion_transitions(std::istream &ftransitiondata, const int tottra for (int i = 0; i < tottransitions_in_file; i++) { int lower_in = -1; int upper_in = -1; - double A = 0; - double coll_str = -1.; + float A = 0; + float coll_str = -1.; int intforbidden = 0; assert_always(getline(ftransitiondata, line)); if (i == 0) { - std::stringstream ss(line); + std::istringstream ss(line); std::string word; - int word_count = 0; + int column_count = 0; while (ss >> word) { - word_count++; + column_count++; } - assert_always(word_count == 4 || word_count == 5); - oldtransitionformat = (word_count == 4); + assert_always(column_count == 4 || column_count == 5); + oldtransitionformat = (column_count == 4); } if (!oldtransitionformat) { - assert_always(sscanf(line.c_str(), "%d %d %lg %lg %d", &lower_in, &upper_in, &A, &coll_str, &intforbidden) == - 5); + assert_always(std::istringstream(line) >> lower_in >> upper_in >> A >> coll_str >> intforbidden); } else { int transindex = 0; // not used - assert_always(sscanf(line.c_str(), "%d %d %d %lg", &transindex, &lower_in, &upper_in, &A) == 4); + assert_always(std::istringstream(line) >> transindex >> lower_in >> upper_in >> A); } const int lower = lower_in - groundstate_index_in; const int upper = upper_in - groundstate_index_in; @@ -451,6 +453,7 @@ static void read_ion_transitions(std::istream &ftransitiondata, const int tottra // this entire block can be removed if we don't want to add in extra collisonal // transitions between levels if (prev_lower < nlevels_requiretransitions) { + assert_always(prev_lower >= 0); int stoplevel = 0; if (lower == prev_lower && upper > prev_upper + 1) { // same lower level, but some upper levels were skipped over @@ -472,7 +475,6 @@ static void read_ion_transitions(std::istream &ftransitiondata, const int tottra // printout("+adding transition index %d Z=%02d ionstage %d lower %d upper %d\n", i, Z, ionstage, prev_lower, // tmplevel); (*tottransitions)++; - assert_always(prev_lower >= 0); assert_always(tmplevel >= 0); transitiontable.push_back( {.lower = prev_lower, .upper = tmplevel, .A = 0., .coll_str = -2., .forbidden = true}); @@ -574,11 +576,11 @@ static void add_transitions_to_unsorted_linelist(const int element, const int io totupdowntrans += 2; if (pass == 1 && globals::rank_in_node == 0) { - const double A_ul = transitiontable[ii].A; + const float A_ul = transitiontable[ii].A; const float coll_str = transitiontable[ii].coll_str; - const double g = stat_weight(element, ion, level) / stat_weight(element, ion, targetlevel); - const float f_ul = g * ME * pow(CLIGHT, 3) / (8 * pow(QE * nu_trans * PI, 2)) * A_ul; + const auto g_ratio = stat_weight(element, ion, level) / stat_weight(element, ion, targetlevel); + const float f_ul = g_ratio * ME * pow(CLIGHT, 3) / (8 * pow(QE * nu_trans * PI, 2)) * A_ul; assert_always(std::isfinite(f_ul)); // printout("lineindex %d, element %d, ion %d, lower %d, upper %d, nu @@ -586,7 +588,7 @@ static void add_transitions_to_unsorted_linelist(const int element, const int io temp_linelist.push_back({ .nu = nu_trans, - .einstein_A = static_cast(A_ul), + .einstein_A = A_ul, .elementindex = element, .ionindex = ion, .upperlevelindex = level, @@ -620,11 +622,11 @@ static void add_transitions_to_unsorted_linelist(const int element, const int io // This is a new branch to deal with lines that have different types of transition. It should trip after a // transition is already known. const int linelistindex = transitions[level].to[level - targetlevel - 1]; - const double A_ul = transitiontable[ii].A; + const float A_ul = transitiontable[ii].A; const float coll_str = transitiontable[ii].coll_str; - const double g = stat_weight(element, ion, level) / stat_weight(element, ion, targetlevel); - const float f_ul = g * ME * pow(CLIGHT, 3) / (8 * pow(QE * nu_trans * PI, 2)) * A_ul; + const auto g_ratio = stat_weight(element, ion, level) / stat_weight(element, ion, targetlevel); + const float f_ul = g_ratio * ME * pow(CLIGHT, 3) / (8 * pow(QE * nu_trans * PI, 2)) * A_ul; if ((temp_linelist[linelistindex].elementindex != element) || (temp_linelist[linelistindex].ionindex != ion) || (temp_linelist[linelistindex].upperlevelindex != level) || @@ -647,12 +649,12 @@ static void add_transitions_to_unsorted_linelist(const int element, const int io const int nloweruptrans = get_nuptrans(element, ion, targetlevel) + 1; auto &downtransition = globals::elements[element].ions[ion].levels[level].downtrans[nupperdowntrans - 1]; - downtransition.einstein_A += static_cast(A_ul); + downtransition.einstein_A += A_ul; downtransition.osc_strength += f_ul; downtransition.coll_str = std::max(downtransition.coll_str, coll_str); auto &uptransition = globals::elements[element].ions[ion].levels[targetlevel].uptrans[nloweruptrans - 1]; - uptransition.einstein_A += static_cast(A_ul); + uptransition.einstein_A += A_ul; uptransition.osc_strength += f_ul; uptransition.coll_str = std::max(uptransition.coll_str, coll_str); } @@ -708,35 +710,32 @@ static void read_atomicdata_files() { int totaluptrans = 0; int totaldowntrans = 0; - FILE *compositiondata = fopen_required("compositiondata.txt", "r"); + auto compositiondata = fstream_required("compositiondata.txt", std::ios::in); - FILE *adata = fopen_required("adata.txt", "r"); + auto adata = fstream_required("adata.txt", std::ios::in); printout("single_level_top_ion: %s\n", single_level_top_ion ? "true" : "false"); printout("single_ground_level: %s\n", single_ground_level ? "true" : "false"); /// initialize atomic data structure to number of elements int nelements_in = 0; - assert_always(fscanf(compositiondata, "%d", &nelements_in) == 1); + assert_always(compositiondata >> nelements_in); set_nelements(nelements_in); - globals::elements = static_cast(calloc(get_nelements(), sizeof(elementlist_entry))); - assert_always(globals::elements != nullptr); /// Initialize the linelist std::vector temp_linelist; + std::vector transitiontable; + /// temperature to determine relevant ionstages int T_preset = 0; - assert_always(fscanf(compositiondata, "%d", &T_preset) == 1); - int homogeneous_abundances_in = 0; - assert_always(fscanf(compositiondata, "%d", &homogeneous_abundances_in) == 1); - globals::homogeneous_abundances = (homogeneous_abundances_in != 0); - if (globals::homogeneous_abundances) { - printout("[info] read_atomicdata: homogeneous abundances as defined in compositiondata.txt are active\n"); - } + assert_always(compositiondata >> T_preset); + assert_always(T_preset == 0); // no longer in use + int homogeneous_abundances = 0; + assert_always(compositiondata >> homogeneous_abundances); + assert_always(homogeneous_abundances == 0); // no longer in use /// open transition data file - std::ifstream ftransitiondata("transitiondata.txt"); - assert_always(ftransitiondata.is_open()); + auto ftransitiondata = fstream_required("transitiondata.txt", std::ios::in); int lineindex = 0; /// counter to determine the total number of lines int uniqueionindex = 0; // index into list of all ions of all elements @@ -751,8 +750,8 @@ static void read_atomicdata_files() { int nlevelsmax_readin = 0; double abundance = NAN; double mass_amu = NAN; - assert_always(fscanf(compositiondata, "%d %d %d %d %d %lg %lg", &Z, &nions, &lowermost_ionstage, - &uppermost_ionstage, &nlevelsmax_readin, &abundance, &mass_amu) == 7); + assert_always(compositiondata >> Z >> nions >> lowermost_ionstage >> uppermost_ionstage >> nlevelsmax_readin >> + abundance >> mass_amu); printout("readin compositiondata: next element Z %d, nions %d, lowermost %d, uppermost %d, nlevelsmax %d\n", Z, nions, lowermost_ionstage, uppermost_ionstage, nlevelsmax_readin); assert_always(Z > 0); @@ -761,15 +760,11 @@ static void read_atomicdata_files() { assert_always(abundance >= 0); assert_always(mass_amu >= 0); - update_max_nions(nions); - assert_always(nions <= get_max_nions()); - /// write this element's data to memory globals::elements[element].anumber = Z; globals::elements[element].nions = nions; globals::elements[element].abundance = abundance; /// abundances are expected to be given by mass globals::elements[element].initstablemeannucmass = mass_amu * MH; - increase_includedions(nions); /// Initialize the elements ionlist globals::elements[element].ions = static_cast(calloc(nions, sizeof(ionlist_entry))); @@ -803,11 +798,15 @@ static void read_atomicdata_files() { double statweight = NAN; int levelindex = 0; int ntransitions = 0; - assert_always( - fscanf(adata, "%d %lg %lg %d%*[^\n]\n", &levelindex, &levelenergy, &statweight, &ntransitions) == 4); + std::string line; + std::getline(adata, line); + + assert_always(std::istringstream(line) >> levelindex >> levelenergy >> statweight >> ntransitions); } - assert_always(fscanf(adata, "%d %d %d %lg\n", &adata_Z_in, &ionstage, &nlevels, &ionpot) == 4); + std::string line; + assert_always(get_noncommentline(adata, line)); + assert_always(std::istringstream(line) >> adata_Z_in >> ionstage >> nlevels >> ionpot); } printout("adata header matched: Z %d, ionstage %d, nlevels %d\n", adata_Z_in, ionstage, nlevels); @@ -845,9 +844,8 @@ static void read_atomicdata_files() { for (int i = 0; i < tottransitions_in_file; i++) { assert_always(getline(ftransitiondata, line)); } - assert_always(get_noncommentline(ftransitiondata, line)); - assert_always( - sscanf(line.c_str(), "%d %d %d", &transdata_Z_in, &transdata_ionstage_in, &tottransitions_in_file) == 3); + assert_always(get_noncommentline(ftransitiondata, line)); // get_noncommentline to skip over blank lines + assert_always(std::istringstream(line) >> transdata_Z_in >> transdata_ionstage_in >> tottransitions_in_file); } printout("transdata header matched: transdata_Z_in %d, transdata_ionstage_in %d, tottransitions %d\n", @@ -863,6 +861,7 @@ static void read_atomicdata_files() { globals::elements[element].ions[ion].ionpot = ionpot * EV; globals::elements[element].ions[ion].nlevels_groundterm = -1; globals::elements[element].ions[ion].uniqueionindex = uniqueionindex; + globals::elements[element].ions[ion].first_nlte = -1; globals::elements[element].ions[ion].Alpha_sp = static_cast(calloc(TABLESIZE, sizeof(float))); assert_always(globals::elements[element].ions[ion].Alpha_sp != nullptr); @@ -886,10 +885,6 @@ static void read_atomicdata_files() { assert_always(transdata_Z_in == Z); assert_always(transdata_ionstage_in == ionstage); - /// read in the level and transition data for this ion - std::vector transitiontable; - transitiontable.reserve(tottransitions); - /// load transition table for the CURRENT ion to temporary memory // first levels will be collisionally @@ -929,9 +924,6 @@ static void read_atomicdata_files() { uniqueionindex++; } } - fclose(adata); - ftransitiondata.close(); - fclose(compositiondata); printout("nbfcheck %d\n", nbfcheck); /// Save the linecounters value to the global variable containing the number of lines @@ -1028,10 +1020,10 @@ static void read_atomicdata_files() { // fclose(linelist_file); // } - printout("establish connection between transitions and sorted linelist..."); + printout("establishing connection between transitions and sorted linelist...\n"); time_t const time_start_establish_linelist_connections = time(nullptr); - for (int lineindex = 0; lineindex < globals::nlines; lineindex++) { + for (lineindex = 0; lineindex < globals::nlines; lineindex++) { const auto &line = globals::linelist[lineindex]; const int element = line.elementindex; const int ion = line.ionindex; @@ -1044,7 +1036,7 @@ static void read_atomicdata_files() { const int nupperdowntrans = get_ndowntrans(element, ion, upperlevel); auto *downtranslist = globals::elements[element].ions[ion].levels[upperlevel].downtrans; auto *downtrans = std::find_if(downtranslist, downtranslist + nupperdowntrans, - [=](auto &downtrans) { return downtrans.targetlevelindex == lowerlevel; }); + [=](const auto &downtrans) { return downtrans.targetlevelindex == lowerlevel; }); assert_always(downtrans != (downtranslist + nupperdowntrans)); // assert_always(downtrans->targetlevelindex == lowerlevel); downtrans->lineindex = lineindex; @@ -1052,13 +1044,13 @@ static void read_atomicdata_files() { const int nloweruptrans = get_nuptrans(element, ion, lowerlevel); auto *uptranslist = globals::elements[element].ions[ion].levels[lowerlevel].uptrans; auto *uptrans = std::find_if(uptranslist, uptranslist + nloweruptrans, - [=](auto &uptrans) { return uptrans.targetlevelindex == upperlevel; }); + [=](const auto &uptrans) { return uptrans.targetlevelindex == upperlevel; }); assert_always(uptrans != (uptranslist + nloweruptrans)); // assert_always(uptrans->targetlevelindex == upperlevel); uptrans->lineindex = lineindex; } - printout("took %ds\n", time(nullptr) - time_start_establish_linelist_connections); + printout(" took %ds\n", time(nullptr) - time_start_establish_linelist_connections); for (int element = 0; element < get_nelements(); element++) { const int nions = get_nions(element); @@ -1144,7 +1136,7 @@ static auto search_groundphixslist(double nu_edge, int *index_in_groundlevelcont index = -1; *index_in_groundlevelcontestimator = -1; } else { - int i = 1; + int i; int element = -1; int ion = -1; for (i = 1; i < globals::nbfcontinua_ground; i++) { @@ -1155,7 +1147,7 @@ static auto search_groundphixslist(double nu_edge, int *index_in_groundlevelcont if (i == globals::nbfcontinua_ground) { element = globals::groundcont[i - 1].element; ion = globals::groundcont[i - 1].ion; - int const level = globals::groundcont[i - 1].level; + const int level = globals::groundcont[i - 1].level; if (element == el && ion == in && level == ll) { index = i - 1; } else { @@ -1403,8 +1395,8 @@ static void setup_phixs_list() { } if (globals::nbfcontinua > 0) { - globals::phixslist[itid].kappa_bf_sum = static_cast(malloc(globals::nbfcontinua * sizeof(double))); - assert_always(globals::phixslist[itid].kappa_bf_sum != nullptr); + globals::phixslist[itid].chi_bf_sum = static_cast(malloc(globals::nbfcontinua * sizeof(double))); + assert_always(globals::phixslist[itid].chi_bf_sum != nullptr); if constexpr (DETAILED_BF_ESTIMATORS_ON) { globals::phixslist[itid].gamma_contr = static_cast(malloc(globals::nbfcontinua * sizeof(double))); @@ -1412,18 +1404,18 @@ static void setup_phixs_list() { } for (int allcontindex = 0; allcontindex < globals::nbfcontinua; allcontindex++) { - globals::phixslist[itid].kappa_bf_sum[allcontindex] = 0.; + globals::phixslist[itid].chi_bf_sum[allcontindex] = 0.; if constexpr (DETAILED_BF_ESTIMATORS_ON) { globals::phixslist[itid].gamma_contr[allcontindex] = 0.; } } } else { - globals::phixslist[itid].kappa_bf_sum = nullptr; + globals::phixslist[itid].chi_bf_sum = nullptr; globals::phixslist[itid].gamma_contr = nullptr; } - printout("[info] mem_usage: phixslist[tid].kappa_bf_contr for thread %d occupies %.3f MB\n", itid, + printout("[info] mem_usage: phixslist[tid].chi_bf_contr for thread %d occupies %.3f MB\n", itid, globals::nbfcontinua * sizeof(double) / 1024. / 1024.); } @@ -1571,62 +1563,7 @@ static void setup_phixs_list() { globals::allcont = nonconstallcont; nonconstallcont = nullptr; - size_t mem_usage_photoionluts = 2 * TABLESIZE * globals::nbfcontinua * sizeof(double); - - if (globals::nbfcontinua > 0) { -#ifdef MPI_ON - MPI_Win win = MPI_WIN_NULL; - MPI_Aint size = (globals::rank_in_node == 0) ? TABLESIZE * globals::nbfcontinua * sizeof(double) : 0; - int disp_unit = sizeof(double); - assert_always(MPI_Win_allocate_shared(size, disp_unit, MPI_INFO_NULL, globals::mpi_comm_node, - &globals::spontrecombcoeff, &win) == MPI_SUCCESS); - assert_always(MPI_Win_shared_query(win, 0, &size, &disp_unit, &globals::spontrecombcoeff) == MPI_SUCCESS); -#else - globals::spontrecombcoeff = static_cast(malloc(TABLESIZE * globals::nbfcontinua * sizeof(double))); -#endif - assert_always(globals::spontrecombcoeff != nullptr); - - if constexpr (USE_LUT_PHOTOION) { -#ifdef MPI_ON - size = (globals::rank_in_node == 0) ? TABLESIZE * globals::nbfcontinua * sizeof(double) : 0; - assert_always(MPI_Win_allocate_shared(size, disp_unit, MPI_INFO_NULL, globals::mpi_comm_node, - &globals::corrphotoioncoeff, &win) == MPI_SUCCESS); - assert_always(MPI_Win_shared_query(win, 0, &size, &disp_unit, &globals::corrphotoioncoeff) == MPI_SUCCESS); -#else - globals::corrphotoioncoeff = static_cast(malloc(TABLESIZE * globals::nbfcontinua * sizeof(double))); -#endif - assert_always(globals::corrphotoioncoeff != nullptr); - mem_usage_photoionluts += TABLESIZE * globals::nbfcontinua * sizeof(double); - } - - if constexpr (USE_LUT_BFHEATING) { -#ifdef MPI_ON - size = (globals::rank_in_node == 0) ? TABLESIZE * globals::nbfcontinua * sizeof(double) : 0; - assert_always(MPI_Win_allocate_shared(size, disp_unit, MPI_INFO_NULL, globals::mpi_comm_node, - &globals::bfheating_coeff, &win) == MPI_SUCCESS); - assert_always(MPI_Win_shared_query(win, 0, &size, &disp_unit, &globals::bfheating_coeff) == MPI_SUCCESS); -#else - globals::bfheating_coeff = static_cast(malloc(TABLESIZE * globals::nbfcontinua * sizeof(double))); -#endif - assert_always(globals::bfheating_coeff != nullptr); - mem_usage_photoionluts += TABLESIZE * globals::nbfcontinua * sizeof(double); - } - -#ifdef MPI_ON - size = (globals::rank_in_node == 0) ? TABLESIZE * globals::nbfcontinua * sizeof(double) : 0; - assert_always(MPI_Win_allocate_shared(size, disp_unit, MPI_INFO_NULL, globals::mpi_comm_node, - &globals::bfcooling_coeff, &win) == MPI_SUCCESS); - assert_always(MPI_Win_shared_query(win, 0, &size, &disp_unit, &globals::bfcooling_coeff) == MPI_SUCCESS); -#else - globals::bfcooling_coeff = static_cast(malloc(TABLESIZE * globals::nbfcontinua * sizeof(double))); -#endif - assert_always(globals::bfcooling_coeff != nullptr); - } - - printout( - "[info] mem_usage: lookup tables derived from photoionisation (spontrecombcoeff, bfcooling and " - "corrphotoioncoeff/bfheating if enabled) occupy %.3f MB\n", - mem_usage_photoionluts / 1024. / 1024.); + setup_photoion_luts(); } static void read_atomicdata() { @@ -1649,6 +1586,8 @@ static void read_atomicdata() { /// Printout some information about the read-in model atom + update_includedions_maxnions(); + int includedlevels = 0; int includedionisinglevels = 0; int includedboundboundtransitions = 0; @@ -1694,8 +1633,12 @@ static void read_atomicdata() { globals::total_nlte_levels = 0; int n_super_levels = 0; - if (NLTE_POPS_ON) { - for (int element = 0; element < get_nelements(); element++) { + for (int element = 0; element < get_nelements(); element++) { + globals::elements[element].has_nlte_levels = elem_has_nlte_levels_search(element); + } + + for (int element = 0; element < get_nelements(); element++) { + if (elem_has_nlte_levels(element)) { const int nions = get_nions(element); for (int ion = 0; ion < nions; ion++) { globals::elements[element].ions[ion].first_nlte = globals::total_nlte_levels; @@ -1707,6 +1650,7 @@ static void read_atomicdata() { globals::total_nlte_levels++; } } + globals::elements[element].ions[ion].nlevels_nlte = fullnlteexcitedlevelcount; const bool has_superlevel = (nlevels > (fullnlteexcitedlevelcount + 1)); if (has_superlevel) { @@ -1717,8 +1661,6 @@ static void read_atomicdata() { n_super_levels++; } - globals::elements[element].ions[ion].nlevels_nlte = fullnlteexcitedlevelcount; - assert_always(has_superlevel == ion_has_superlevel(element, ion)); printout("[input] element %2d Z=%2d ion_stage %2d has %5d NLTE excited levels%s. Starting at %d\n", element, @@ -1734,10 +1676,8 @@ static void read_atomicdata() { void input(int rank) /// To govern the input. For now hardwire everything. { - globals::homogeneous_abundances = false; - globals::n_titer = 1; - globals::initial_iteration = false; + globals::lte_iteration = false; printout("[info] input: do n_titer %d iterations per timestep\n", globals::n_titer); if (globals::n_titer > 1) { @@ -1775,17 +1715,11 @@ void input(int rank) grid::read_ejecta_model(); } -static auto getline(std::istream &input, std::string &line) -> bool -// return true if line read, false if not (EOF) -{ - return !(!std::getline(input, line)); -} - -auto get_noncommentline(std::istream &input, std::string &line) -> bool +auto get_noncommentline(std::fstream &input, std::string &line) -> bool // read the next line, skipping any comment lines beginning with '#' { while (true) { - bool const linefound = getline(input, line); + const bool linefound = !(!std::getline(input, line)); // printout("LINE: >%s< linefound: %s commentonly: %s \n", line.c_str(), linefound ? "true" : "false", // lineiscommentonly(line) ? "true" : "false"); if (!linefound) { @@ -1800,27 +1734,22 @@ auto get_noncommentline(std::istream &input, std::string &line) -> bool void read_parameterfile(int rank) /// Subroutine to read in input parameters from input.txt. { - unsigned long pre_zseed = 0; + uint_least64_t pre_zseed = 0; - std::ifstream file("input.txt"); - assert_always(file.is_open()); + auto file = fstream_required("input.txt", std::ios::in); std::string line; assert_always(get_noncommentline(file, line)); - long zseed_input = 0; - std::stringstream(line) >> zseed_input; + uint_fast64_t zseed_input = 0; + std::istringstream(line) >> zseed_input; if (zseed_input > 0) { pre_zseed = zseed_input; // random number seed printout("using input.txt specified random number seed of %lu\n", pre_zseed); } else { - if constexpr (USE_GSL_RANDOM) { - pre_zseed = time(nullptr); - } else { - pre_zseed = std::random_device{}(); - } + pre_zseed = std::random_device{}(); printout("randomly-generated random number seed is %lu\n", pre_zseed); } @@ -1831,11 +1760,10 @@ void read_parameterfile(int rank) /// For MPI parallelisation, the random seed is changed based on the rank of the process /// For OpenMP parallelisation rng is a threadprivate variable and the seed changed according /// to the thread-ID tid. - const uint_fast64_t zseed = pre_zseed + (13 * rank) + (17 * tid); /* rnum generator seed */ + const auto zseed = pre_zseed + 13 * (rank * get_num_threads() + tid); printout("rank %d: thread %d has zseed %lu\n", rank, tid, zseed); - /// start by setting up the randon number generator rng_init(zseed); - /// call it a few times to get it in motion. + /// call it a few times for (int n = 0; n < 100; n++) { rng_uniform(); } @@ -1844,21 +1772,21 @@ void read_parameterfile(int rank) #endif assert_always(get_noncommentline(file, line)); - std::stringstream(line) >> globals::ntstep; // number of time steps - assert_always(globals::ntstep > 0); + std::istringstream(line) >> globals::ntimesteps; // number of time steps + assert_always(globals::ntimesteps > 0); assert_always(get_noncommentline(file, line)); - // printout("line %s\n", line.c_str()); - std::stringstream(line) >> globals::itstep >> globals::ftstep; // number of start and end time step - printout("input: itstep %d ftstep %d\n", globals::itstep, globals::ftstep); - assert_always(globals::itstep < globals::ntstep); - assert_always(globals::itstep <= globals::ftstep); - assert_always(globals::ftstep <= globals::ntstep); + std::istringstream(line) >> globals::timestep_initial >> + globals::timestep_finish; // number of start and end time step + printout("input: timestep_start %d timestep_finish %d\n", globals::timestep_initial, globals::timestep_finish); + assert_always(globals::timestep_initial < globals::ntimesteps); + assert_always(globals::timestep_initial <= globals::timestep_finish); + assert_always(globals::timestep_finish <= globals::ntimesteps); double tmin_days = 0.; double tmax_days = 0.; assert_always(get_noncommentline(file, line)); - std::stringstream(line) >> tmin_days >> tmax_days; // start and end times + std::istringstream(line) >> tmin_days >> tmax_days; // start and end times assert_always(tmin_days > 0); assert_always(tmax_days > 0); assert_always(tmin_days < tmax_days); @@ -1873,13 +1801,13 @@ void read_parameterfile(int rank) assert_always(get_noncommentline(file, line)); // model dimensions int dum1 = 0; - std::stringstream(line) >> dum1; + std::istringstream(line) >> dum1; if (dum1 == 1) { - set_model_type(grid::RHO_1D_READ); + grid::set_model_type(GRID_SPHERICAL1D); } else if (dum1 == 2) { - set_model_type(grid::RHO_2D_READ); + grid::set_model_type(GRID_CYLINDRICAL2D); } else if (dum1 == 3) { - set_model_type(grid::RHO_3D_READ); + grid::set_model_type(GRID_CARTESIAN3D); } assert_always(get_noncommentline(file, line)); // UNUSED compute the r-light curve? @@ -1889,11 +1817,11 @@ void read_parameterfile(int rank) assert_always(get_noncommentline(file, line)); // UNUSED change speed of light assert_always(get_noncommentline(file, line)); - std::stringstream(line) >> globals::gamma_grey; // use grey opacity for gammas? + std::istringstream(line) >> globals::gamma_kappagrey; // use grey opacity for gammas? float syn_dir_in[3]; assert_always(get_noncommentline(file, line)); - std::stringstream(line) >> syn_dir_in[0] >> syn_dir_in[1] >> syn_dir_in[2]; // components of syn_dir + std::istringstream(line) >> syn_dir_in[0] >> syn_dir_in[1] >> syn_dir_in[2]; // components of syn_dir const double rr = (syn_dir_in[0] * syn_dir_in[0]) + (syn_dir_in[1] * syn_dir_in[1]) + (syn_dir_in[2] * syn_dir_in[2]); // ensure that this vector is normalised. @@ -1910,42 +1838,42 @@ void read_parameterfile(int rank) } assert_always(get_noncommentline(file, line)); - std::stringstream(line) >> globals::opacity_case; // opacity choice + std::istringstream(line) >> globals::opacity_case; // opacity choice assert_always(get_noncommentline(file, line)); - std::stringstream(line) >> globals::rho_crit_para; // free parameter for calculation of rho_crit + std::istringstream(line) >> globals::rho_crit_para; // free parameter for calculation of rho_crit printout("input: rho_crit_para %g\n", globals::rho_crit_para); /// he calculation of rho_crit itself depends on the time, therfore it happens in grid_init and update_grid assert_always(get_noncommentline(file, line)); int debug_packet = 0; - std::stringstream(line) >> debug_packet; // activate debug output for packet + std::istringstream(line) >> debug_packet; // activate debug output for packet assert_always(debug_packet == -1); // select a negative value to deactivate // Do we start a new simulation or, continue another one? int continue_flag = 0; assert_always(get_noncommentline(file, line)); - std::stringstream(line) >> continue_flag; + std::istringstream(line) >> continue_flag; globals::simulation_continued_from_saved = (continue_flag == 1); if (globals::simulation_continued_from_saved) { printout("input: resuming simulation from saved point\n"); } else { printout("input: starting a new simulation\n"); - assert_always(globals::itstep == 0); + assert_always(globals::timestep_initial == 0); } /// Wavelength (in Angstroms) at which the parameterisation of the radiation field /// switches from the nebular approximation to LTE. float dum2 = NAN; assert_always(get_noncommentline(file, line)); - std::stringstream(line) >> dum2; // free parameter for calculation of rho_crit + std::istringstream(line) >> dum2; // free parameter for calculation of rho_crit globals::nu_rfcut = CLIGHT / (dum2 * 1e-8); printout("input: nu_rfcut %g\n", globals::nu_rfcut); /// Sets the number of initial LTE timesteps for NLTE runs assert_always(get_noncommentline(file, line)); - std::stringstream(line) >> globals::num_lte_timesteps; + std::istringstream(line) >> globals::num_lte_timesteps; printout("input: doing the first %d timesteps in LTE\n", globals::num_lte_timesteps); if (NT_ON) { @@ -1958,27 +1886,27 @@ void read_parameterfile(int rank) printout("input: No non-thermal ionisation is used in this run.\n"); } - if (!USE_LUT_PHOTOION) { - printout( - "Corrphotoioncoeff is calculated from the radiation field at each timestep in each modelgrid cell (no " - "LUT).\n"); - } else { + if (USE_LUT_PHOTOION) { printout( "Corrphotoioncoeff is calculated from LTE lookup tables (ratecoeff.dat) and corrphotoionrenorm " "estimator.\n"); + } else { + printout( + "Corrphotoioncoeff is calculated from the radiation field at each timestep in each modelgrid cell (no " + "LUT).\n"); } - if (!USE_LUT_BFHEATING) { + if (USE_LUT_BFHEATING) { + printout("bfheating coefficients are calculated from LTE lookup tables (ratecoeff.dat) and bfheatingestimator.\n"); + } else { printout( "bfheating coefficients are calculated from the radiation field at each timestep in each modelgrid cell (no " "LUT).\n"); - } else { - printout("bfheating coefficients are calculated from LTE lookup tables (ratecoeff.dat) and bfheatingestimator.\n"); } /// Set up initial grey approximation? assert_always(get_noncommentline(file, line)); - std::stringstream(line) >> globals::cell_is_optically_thick >> globals::num_grey_timesteps; + std::istringstream(line) >> globals::cell_is_optically_thick >> globals::num_grey_timesteps; printout( "input: cells with Thomson optical depth > %g are treated in grey approximation for the first %d timesteps\n", globals::cell_is_optically_thick, globals::num_grey_timesteps); @@ -1986,16 +1914,16 @@ void read_parameterfile(int rank) /// Limit the number of bf-continua assert_always(get_noncommentline(file, line)); int max_bf_continua = 0; - std::stringstream(line) >> max_bf_continua; + std::istringstream(line) >> max_bf_continua; assert_always(max_bf_continua == -1); /// for exspec: read number of MPI tasks assert_always(get_noncommentline(file, line)); - std::stringstream(line) >> globals::nprocs_exspec; + std::istringstream(line) >> globals::nprocs_exspec; /// Extract line-of-sight dependent information of last emission for spectrum_res assert_always(get_noncommentline(file, line)); - std::stringstream(line) >> dum1; + std::istringstream(line) >> dum1; globals::do_emission_res = (dum1 != 0); /// To reduce the work imbalance between different MPI tasks I introduced a diffusion @@ -2006,7 +1934,7 @@ void read_parameterfile(int rank) /// kpkts live. Parameter two (an int) gives the number of time steps for which we /// want to use this approximation assert_always(get_noncommentline(file, line)); - std::stringstream(line) >> globals::kpktdiffusion_timescale >> globals::n_kpktdiffusion_timesteps; + std::istringstream(line) >> globals::kpktdiffusion_timescale >> globals::n_kpktdiffusion_timesteps; printout("input: kpkts diffuse %g of a time step's length for the first %d time steps\n", globals::kpktdiffusion_timescale, globals::n_kpktdiffusion_timesteps); @@ -2054,7 +1982,7 @@ void update_parameterfile(int nts) if (nts >= 0) { if (noncomment_linenum == 2) { /// Number of start and end time step - snprintf(c_line, 1024, "%d %d", nts, globals::ftstep); + snprintf(c_line, 1024, "%d %d", nts, globals::timestep_finish); // line.assign(c_line); line.replace(line.begin(), line.end(), c_line); } else if (noncomment_linenum == 16) { @@ -2102,32 +2030,32 @@ void update_parameterfile(int nts) } void time_init() -// Subroutine to define the time steps. +// define the time steps { - /// t=globals::tmin is the start of the calcualtion. t=globals::tmax is the end of the calculation. - /// globals::ntstep is the number of time steps wanted. + /// t=globals::tmin is the start of the calculation. t=globals::tmax is the end of the calculation. + /// globals::ntimesteps is the number of time steps - globals::time_step = static_cast(malloc((globals::ntstep + 1) * sizeof(struct time))); + globals::timesteps = std::make_unique(globals::ntimesteps + 1); /// Now set the individual time steps switch (TIMESTEP_SIZE_METHOD) { case TIMESTEP_SIZES_LOGARITHMIC: { - for (int n = 0; n < globals::ntstep; n++) { // For logarithmic steps, the logarithmic inverval will be - const double dlogt = (log(globals::tmax) - log(globals::tmin)) / globals::ntstep; - globals::time_step[n].start = globals::tmin * exp(n * dlogt); - globals::time_step[n].mid = globals::tmin * exp((n + 0.5) * dlogt); - globals::time_step[n].width = (globals::tmin * exp((n + 1) * dlogt)) - globals::time_step[n].start; + for (int n = 0; n < globals::ntimesteps; n++) { // For logarithmic steps, the logarithmic inverval will be + const double dlogt = (log(globals::tmax) - log(globals::tmin)) / globals::ntimesteps; + globals::timesteps[n].start = globals::tmin * exp(n * dlogt); + globals::timesteps[n].mid = globals::tmin * exp((n + 0.5) * dlogt); + globals::timesteps[n].width = (globals::tmin * exp((n + 1) * dlogt)) - globals::timesteps[n].start; } break; } case TIMESTEP_SIZES_CONSTANT: { - for (int n = 0; n < globals::ntstep; n++) { + for (int n = 0; n < globals::ntimesteps; n++) { // for constant timesteps - const double dt = (globals::tmax - globals::tmin) / globals::ntstep; - globals::time_step[n].start = globals::tmin + n * dt; - globals::time_step[n].width = dt; - globals::time_step[n].mid = globals::time_step[n].start + 0.5 * globals::time_step[n].width; + const double dt = (globals::tmax - globals::tmin) / globals::ntimesteps; + globals::timesteps[n].start = globals::tmin + n * dt; + globals::timesteps[n].width = dt; + globals::timesteps[n].mid = globals::timesteps[n].start + 0.5 * globals::timesteps[n].width; } break; } @@ -2141,25 +2069,25 @@ void time_init() const int nts_fixed = ceil((globals::tmax - t_transition) / maxtsdelta); const double fixed_tsdelta = (globals::tmax - t_transition) / nts_fixed; assert_always(nts_fixed > 0); - assert_always(nts_fixed < globals::ntstep); - const int nts_log = globals::ntstep - nts_fixed; + assert_always(nts_fixed < globals::ntimesteps); + const int nts_log = globals::ntimesteps - nts_fixed; assert_always(nts_log > 0); - assert_always(nts_log < globals::ntstep); - assert_always((nts_log + nts_fixed) == globals::ntstep); - for (int n = 0; n < globals::ntstep; n++) { + assert_always(nts_log < globals::ntimesteps); + assert_always((nts_log + nts_fixed) == globals::ntimesteps); + for (int n = 0; n < globals::ntimesteps; n++) { if (n < nts_log) { // For logarithmic steps, the logarithmic inverval will be const double dlogt = (log(t_transition) - log(globals::tmin)) / nts_log; - globals::time_step[n].start = globals::tmin * exp(n * dlogt); - globals::time_step[n].mid = globals::tmin * exp((n + 0.5) * dlogt); - globals::time_step[n].width = (globals::tmin * exp((n + 1) * dlogt)) - globals::time_step[n].start; + globals::timesteps[n].start = globals::tmin * exp(n * dlogt); + globals::timesteps[n].mid = globals::tmin * exp((n + 0.5) * dlogt); + globals::timesteps[n].width = (globals::tmin * exp((n + 1) * dlogt)) - globals::timesteps[n].start; } else { // for constant timesteps const double prev_start = - n > 0 ? (globals::time_step[n - 1].start + globals::time_step[n - 1].width) : globals::tmin; - globals::time_step[n].start = prev_start; - globals::time_step[n].width = fixed_tsdelta; - globals::time_step[n].mid = globals::time_step[n].start + 0.5 * globals::time_step[n].width; + n > 0 ? (globals::timesteps[n - 1].start + globals::timesteps[n - 1].width) : globals::tmin; + globals::timesteps[n].start = prev_start; + globals::timesteps[n].width = fixed_tsdelta; + globals::timesteps[n].mid = globals::timesteps[n].start + 0.5 * globals::timesteps[n].width; } } break; @@ -2174,25 +2102,25 @@ void time_init() const int nts_fixed = ceil((t_transition - globals::tmin) / maxtsdelta); const double fixed_tsdelta = (t_transition - globals::tmin) / nts_fixed; assert_always(nts_fixed > 0); - assert_always(nts_fixed < globals::ntstep); - const int nts_log = globals::ntstep - nts_fixed; + assert_always(nts_fixed < globals::ntimesteps); + const int nts_log = globals::ntimesteps - nts_fixed; assert_always(nts_log > 0); - assert_always(nts_log < globals::ntstep); - assert_always((nts_log + nts_fixed) == globals::ntstep); - for (int n = 0; n < globals::ntstep; n++) { + assert_always(nts_log < globals::ntimesteps); + assert_always((nts_log + nts_fixed) == globals::ntimesteps); + for (int n = 0; n < globals::ntimesteps; n++) { if (n < nts_fixed) { // for constant timesteps - globals::time_step[n].start = globals::tmin + n * fixed_tsdelta; - globals::time_step[n].width = fixed_tsdelta; - globals::time_step[n].mid = globals::time_step[n].start + 0.5 * globals::time_step[n].width; + globals::timesteps[n].start = globals::tmin + n * fixed_tsdelta; + globals::timesteps[n].width = fixed_tsdelta; + globals::timesteps[n].mid = globals::timesteps[n].start + 0.5 * globals::timesteps[n].width; } else { // For logarithmic time steps, the logarithmic interval will be const double dlogt = (log(globals::tmax) - log(t_transition)) / nts_log; const double prev_start = - n > 0 ? (globals::time_step[n - 1].start + globals::time_step[n - 1].width) : globals::tmin; - globals::time_step[n].start = prev_start; - globals::time_step[n].width = (t_transition * exp((n - nts_fixed + 1) * dlogt)) - globals::time_step[n].start; - globals::time_step[n].mid = globals::time_step[n].start + 0.5 * globals::time_step[n].width; + n > 0 ? (globals::timesteps[n - 1].start + globals::timesteps[n - 1].width) : globals::tmin; + globals::timesteps[n].start = prev_start; + globals::timesteps[n].width = (t_transition * exp((n - nts_fixed + 1) * dlogt)) - globals::timesteps[n].start; + globals::timesteps[n].mid = globals::timesteps[n].start + 0.5 * globals::timesteps[n].width; } } break; @@ -2204,65 +2132,66 @@ void time_init() // to limit the timestep durations // const double maxt = 0.5 * DAY; - // for (int n = globals::ntstep - 1; n > 0; n--) + // for (int n = globals::ntimesteps - 1; n > 0; n--) // { - // if (globals::time_step[n].width > maxt) + // if (globals::timesteps[n].width > maxt) // { - // const double boundaryshift = globals::time_step[n].width - maxt; - // globals::time_step[n].width -= boundaryshift; - // globals::time_step[n].start += boundaryshift; - // globals::time_step[n - 1].width += boundaryshift; + // const double boundaryshift = globals::timesteps[n].width - maxt; + // globals::timesteps[n].width -= boundaryshift; + // globals::timesteps[n].start += boundaryshift; + // globals::timesteps[n - 1].width += boundaryshift; // } - // else if (n < globals::ntstep - 1 && globals::time_step[n + 1].width > maxt) + // else if (n < globals::ntimesteps - 1 && globals::timesteps[n + 1].width > maxt) // { // printout("TIME: Keeping logarithmic durations for timesteps <= %d\n", n); // } // } - // assert_always(globals::time_step[0].width <= maxt); // no solution is possible with these constraints! + // assert_always(globals::timesteps[0].width <= maxt); // no solution is possible with these constraints! /// and add a dummy timestep which contains the endtime /// of the calculation - globals::time_step[globals::ntstep].start = globals::tmax; - globals::time_step[globals::ntstep].mid = globals::tmax; - globals::time_step[globals::ntstep].width = 0.; + globals::timesteps[globals::ntimesteps].start = globals::tmax; + globals::timesteps[globals::ntimesteps].mid = globals::tmax; + globals::timesteps[globals::ntimesteps].width = 0.; // check consistency of start + width = start_next - for (int n = 1; n < globals::ntstep; n++) { + for (int n = 1; n < globals::ntimesteps; n++) { assert_always( - fabs((globals::time_step[n - 1].start + globals::time_step[n - 1].width) / globals::time_step[n].start) - 1 < + fabs((globals::timesteps[n - 1].start + globals::timesteps[n - 1].width) / globals::timesteps[n].start) - 1 < 0.001); } - assert_always(fabs((globals::time_step[globals::ntstep - 1].start + globals::time_step[globals::ntstep - 1].width) / - globals::tmax) - - 1 < - 0.001); - - for (int n = 0; n < globals::ntstep; n++) { - globals::time_step[n].positron_dep = 0.; - globals::time_step[n].eps_positron_ana_power = 0.; - globals::time_step[n].electron_dep = 0.; - globals::time_step[n].electron_emission = 0.; - globals::time_step[n].eps_electron_ana_power = 0.; - globals::time_step[n].alpha_dep = 0.; - globals::time_step[n].alpha_emission = 0.; - globals::time_step[n].eps_alpha_ana_power = 0.; - globals::time_step[n].gamma_dep = 0.; - globals::time_step[n].gamma_dep_pathint = 0.; - globals::time_step[n].qdot_betaminus = 0.; - globals::time_step[n].qdot_alpha = 0.; - globals::time_step[n].qdot_total = 0.; - globals::time_step[n].gamma_emission = 0.; - globals::time_step[n].cmf_lum = 0.0; - globals::time_step[n].pellet_decays = 0; + assert_always( + fabs((globals::timesteps[globals::ntimesteps - 1].start + globals::timesteps[globals::ntimesteps - 1].width) / + globals::tmax) - + 1 < + 0.001); + + for (int n = 0; n < globals::ntimesteps; n++) { + globals::timesteps[n].positron_dep = 0.; + globals::timesteps[n].eps_positron_ana_power = 0.; + globals::timesteps[n].electron_dep = 0.; + globals::timesteps[n].electron_emission = 0.; + globals::timesteps[n].eps_electron_ana_power = 0.; + globals::timesteps[n].alpha_dep = 0.; + globals::timesteps[n].alpha_emission = 0.; + globals::timesteps[n].eps_alpha_ana_power = 0.; + globals::timesteps[n].gamma_dep = 0.; + globals::timesteps[n].gamma_dep_pathint = 0.; + globals::timesteps[n].qdot_betaminus = 0.; + globals::timesteps[n].qdot_alpha = 0.; + globals::timesteps[n].qdot_total = 0.; + globals::timesteps[n].gamma_emission = 0.; + globals::timesteps[n].cmf_lum = 0.0; + globals::timesteps[n].pellet_decays = 0; } } void write_timestep_file() { FILE *timestepfile = fopen_required("timesteps.out", "w"); fprintf(timestepfile, "#timestep tstart_days tmid_days twidth_days\n"); - for (int n = 0; n < globals::ntstep; n++) { - fprintf(timestepfile, "%d %lg %lg %lg\n", n, globals::time_step[n].start / DAY, globals::time_step[n].mid / DAY, - globals::time_step[n].width / DAY); + for (int n = 0; n < globals::ntimesteps; n++) { + fprintf(timestepfile, "%d %lg %lg %lg\n", n, globals::timesteps[n].start / DAY, globals::timesteps[n].mid / DAY, + globals::timesteps[n].width / DAY); } fclose(timestepfile); -} +} \ No newline at end of file diff --git a/input.h b/input.h index f8d102b2c..49f63025e 100644 --- a/input.h +++ b/input.h @@ -10,17 +10,15 @@ void read_parameterfile(int rank); void update_parameterfile(int nts); void time_init(); void write_timestep_file(); -bool get_noncommentline(std::istream &input, std::string &line); +bool get_noncommentline(std::fstream &input, std::string &line); static inline bool lineiscommentonly(const std::string &line) // return true for whitepace-only lines, and lines that are exclusively whitepace up to a '#' character { - int searchlength = line.find('#'); // ignore anything to the right of a # character - if (searchlength < 0) { - searchlength = line.length(); - } - - for (int i = 0; i < searchlength; i++) { + for (size_t i = 0; i < line.length(); i++) { + if (line[i] == '#') { // anything to the right of a # character doesn't count + return true; + } if (line[i] != ' ') { return false; } diff --git a/kpkt.cc b/kpkt.cc index dc67f7847..f396d4d12 100644 --- a/kpkt.cc +++ b/kpkt.cc @@ -36,142 +36,18 @@ struct cellhistorycoolinglist { static struct cellhistorycoolinglist *coolinglist; -static auto get_ncoolingterms(int element, int ion) -> int { +static auto get_ncoolingterms_ion(int element, int ion) -> int { return globals::elements[element].ions[ion].ncoolingterms; } -static auto get_bfcoolingcoeff(int element, int ion, int level, int phixstargetindex, float T_e) -> double { - const int lowerindex = floor(log(T_e / MINTEMP) / T_step_log); - if (lowerindex < TABLESIZE - 1) { - const int upperindex = lowerindex + 1; - const double T_lower = MINTEMP * exp(lowerindex * T_step_log); - const double T_upper = MINTEMP * exp(upperindex * T_step_log); - - const double f_upper = globals::bfcooling_coeff[get_bflutindex(upperindex, element, ion, level, phixstargetindex)]; - const double f_lower = globals::bfcooling_coeff[get_bflutindex(lowerindex, element, ion, level, phixstargetindex)]; - - return (f_lower + (f_upper - f_lower) / (T_upper - T_lower) * (T_e - T_lower)); - } - return globals::bfcooling_coeff[get_bflutindex(TABLESIZE - 1, element, ion, level, phixstargetindex)]; -} - -void calculate_cooling_rates(const int modelgridindex, struct heatingcoolingrates *heatingcoolingrates) -// Calculate the cooling rates for a given cell and store them for each ion -// optionally store components (ff, bf, collisional) in heatingcoolingrates struct -{ - const auto nne = grid::get_nne(modelgridindex); - const auto T_e = grid::get_Te(modelgridindex); - - double C_ff_all = 0.; /// free-free creation of rpkts - double C_fb_all = 0.; /// free-bound creation of rpkt - double C_exc_all = 0.; /// collisional excitation of macroatoms - double C_ionization_all = 0.; /// collisional ionisation of macroatoms - for (int element = 0; element < get_nelements(); element++) { - const int nions = get_nions(element); - for (int ion = 0; ion < nions; ion++) { - double C_ion = 0.; /// all cooling for an ion - const int nionisinglevels = get_ionisinglevels(element, ion); - const double nncurrention = ionstagepop(modelgridindex, element, ion); - - /// ff creation of rpkt - const int ioncharge = get_ionstage(element, ion) - 1; - if (ioncharge > 0) { - const double C_ff_ion = 1.426e-27 * sqrt(T_e) * pow(ioncharge, 2) * nncurrention * nne; - C_ff_all += C_ff_ion; - C_ion += C_ff_ion; - } - - const int nlevels = get_nlevels(element, ion); - - /// excitation to same ionization stage - /// ----------------------------------- - for (int level = 0; level < nlevels; level++) { - const double nnlevel = get_levelpop(modelgridindex, element, ion, level); - const double epsilon_current = epsilon(element, ion, level); - const double statweight = stat_weight(element, ion, level); - - const int nuptrans = get_nuptrans(element, ion, level); - for (int ii = 0; ii < nuptrans; ii++) { - const int upper = globals::elements[element].ions[ion].levels[level].uptrans[ii].targetlevelindex; - // printout(" excitation to level %d possible\n",upper); - const double epsilon_trans = epsilon(element, ion, upper) - epsilon_current; - const double C = nnlevel * - col_excitation_ratecoeff(T_e, nne, element, ion, level, ii, epsilon_trans, statweight) * - epsilon_trans; - C_exc_all += C; - C_ion += C; - } - } - - if (ion < nions - 1) { - const double nnupperion = ionstagepop(modelgridindex, element, ion + 1); - - for (int level = 0; level < nionisinglevels; level++) { - // printout("[debug] do_kpkt: element %d, ion %d, level %d\n", element, ion, level); - const double epsilon_current = epsilon(element, ion, level); - const double nnlevel = get_levelpop(modelgridindex, element, ion, level); - - /// ionization to higher ionization stage - const int nphixstargets = get_nphixstargets(element, ion, level); - for (int phixstargetindex = 0; phixstargetindex < nphixstargets; phixstargetindex++) { - const int upper = get_phixsupperlevel(element, ion, level, phixstargetindex); - const double epsilon_upper = epsilon(element, ion + 1, upper); - const double epsilon_trans = epsilon_upper - epsilon_current; - // printout("cooling list: col_ionization\n"); - const double C_ionization_ion_thistarget = - nnlevel * col_ionization_ratecoeff(T_e, nne, element, ion, level, phixstargetindex, epsilon_trans) * - epsilon_trans; - C_ionization_all += C_ionization_ion_thistarget; - C_ion += C_ionization_ion_thistarget; - } - } - - /// fb creation of r-pkt - /// free bound rates are calculated from the lower ion, but associated to the higher ion - for (int level = 0; level < nionisinglevels; level++) { - const int nphixstargets = get_nphixstargets(element, ion, level); - for (int phixstargetindex = 0; phixstargetindex < nphixstargets; phixstargetindex++) { - const double pop = (BFCOOLING_USELEVELPOPNOTIONPOP - ? get_levelpop(modelgridindex, element, ion + 1, - get_phixsupperlevel(element, ion, level, phixstargetindex)) - : nnupperion); - - const double C_fb_ion_thistarget = - get_bfcoolingcoeff(element, ion, level, phixstargetindex, T_e) * pop * nne; - C_fb_all += C_fb_ion_thistarget; - C_ion += C_fb_ion_thistarget; - } - } - } - - grid::modelgrid[modelgridindex].cooling_contrib_ion[element][ion] = C_ion; - } - } - - // this loop is made separate for future parallelisation of upper loop. - // the ion contributions must be added in this exact order - double C_total = 0.; - for (int element = 0; element < get_nelements(); element++) { - const int nions = get_nions(element); - for (int ion = 0; ion < nions; ion++) { - C_total += grid::modelgrid[modelgridindex].cooling_contrib_ion[element][ion]; - } - } - grid::modelgrid[modelgridindex].totalcooling = C_total; - - // only used in the T_e solver and write_to_estimators file - if (heatingcoolingrates != nullptr) { - heatingcoolingrates->cooling_collisional = C_exc_all + C_ionization_all; - heatingcoolingrates->cooling_fb = C_fb_all; - heatingcoolingrates->cooling_ff = C_ff_all; - } -} - -static void calculate_kpkt_rates_ion(int modelgridindex, int element, int ion, int indexionstart, int tid) +template +static auto calculate_cooling_rates_ion(const int modelgridindex, const int element, const int ion, + const int indexionstart, const int tid, double *C_ff, double *C_fb, + double *C_exc, double *C_ionization) -> double // calculate the cooling contribution list of individual levels/processes for an ion // oldcoolingsum is the sum of lower ion (of same element or all ions of lower elements) cooling contributions { - const float nne = grid::get_nne(modelgridindex); + const auto nne = grid::get_nne(modelgridindex); const auto T_e = grid::get_Te(modelgridindex); double C_ion = 0.; @@ -180,24 +56,29 @@ static void calculate_kpkt_rates_ion(int modelgridindex, int element, int ion, i const int nions = get_nions(element); const int nionisinglevels = get_ionisinglevels(element, ion); - const double nncurrention = ionstagepop(modelgridindex, element, ion); + const double nncurrention = get_nnion(modelgridindex, element, ion); /// ff creation of rpkt const int ioncharge = get_ionstage(element, ion) - 1; // printout("[debug] ioncharge %d, nncurrention %g, nne %g\n",ion,nncurrention,nne); if (ioncharge > 0) { - const double C = 1.426e-27 * sqrt(T_e) * pow(ioncharge, 2) * nncurrention * nne; - C_ion += C; - globals::cellhistory[tid].cooling_contrib[i] = C_ion; - - assert_testmodeonly(coolinglist[i].type == COOLINGTYPE_FF); - assert_testmodeonly(coolinglist[i].element == element); - assert_testmodeonly(coolinglist[i].ion == ion); - - // if (contrib < oldcoolingsum) printout("contrib %g < oldcoolingsum %g: C%g, element %d, ion %d, level %d, - // coolingtype %d, i %d, low - // %d\n",contrib,oldcoolingsum,C,element,ion,-99,globals::cellhistory[tid].coolinglist[i].type,i,low); - i++; + const double C_ff_ion = 1.426e-27 * sqrt(T_e) * pow(ioncharge, 2) * nncurrention * nne; + C_ion += C_ff_ion; + + if constexpr (update_cooling_contrib_list) { + globals::cellhistory[tid].cooling_contrib[i] = C_ion; + + assert_testmodeonly(coolinglist[i].type == COOLINGTYPE_FF); + assert_testmodeonly(coolinglist[i].element == element); + assert_testmodeonly(coolinglist[i].ion == ion); + + // if (contrib < oldcoolingsum) printout("contrib %g < oldcoolingsum %g: C%g, element %d, ion %d, level %d, + // coolingtype %d, i %d, low + // %d\n",contrib,oldcoolingsum,C,element,ion,-99,globals::cellhistory[tid].coolinglist[i].type,i,low); + i++; + } else { + *C_ff += C_ff_ion; + } } /// excitation to same ionization stage @@ -217,19 +98,24 @@ static void calculate_kpkt_rates_ion(int modelgridindex, int element, int ion, i col_excitation_ratecoeff(T_e, nne, element, ion, level, ii, epsilon_trans, statweight) * epsilon_trans; C_ion += C; + if constexpr (!update_cooling_contrib_list) { + *C_exc += C; + } } - globals::cellhistory[tid].cooling_contrib[i] = C_ion; + if constexpr (update_cooling_contrib_list) { + globals::cellhistory[tid].cooling_contrib[i] = C_ion; - assert_testmodeonly(coolinglist[i].type == COOLINGTYPE_COLLEXC); - assert_testmodeonly(coolinglist[i].element == element); - assert_testmodeonly(coolinglist[i].ion == ion); + assert_testmodeonly(coolinglist[i].type == COOLINGTYPE_COLLEXC); + assert_testmodeonly(coolinglist[i].element == element); + assert_testmodeonly(coolinglist[i].ion == ion); - i++; + i++; + } } } if (ion < nions - 1) { - const double nnupperion = ionstagepop(modelgridindex, element, ion + 1); + const double nnupperion = get_nnion(modelgridindex, element, ion + 1); // ionization to higher ionization stage for (int level = 0; level < nionisinglevels; level++) { @@ -245,15 +131,19 @@ static void calculate_kpkt_rates_ion(int modelgridindex, int element, int ion, i epsilon_trans; C_ion += C; - globals::cellhistory[tid].cooling_contrib[i] = C_ion; + if constexpr (update_cooling_contrib_list) { + globals::cellhistory[tid].cooling_contrib[i] = C_ion; - assert_testmodeonly(coolinglist[i].type == COOLINGTYPE_COLLION); - assert_testmodeonly(coolinglist[i].element == element); - assert_testmodeonly(coolinglist[i].ion == ion); - assert_testmodeonly(coolinglist[i].level == level); - assert_testmodeonly(coolinglist[i].upperlevel == upper); + assert_testmodeonly(coolinglist[i].type == COOLINGTYPE_COLLION); + assert_testmodeonly(coolinglist[i].element == element); + assert_testmodeonly(coolinglist[i].ion == ion); + assert_testmodeonly(coolinglist[i].level == level); + assert_testmodeonly(coolinglist[i].upperlevel == upper); - i++; + i++; + } else { + *C_ionization += C; + } } } @@ -269,24 +159,65 @@ static void calculate_kpkt_rates_ion(int modelgridindex, int element, int ion, i const double C = get_bfcoolingcoeff(element, ion, level, phixstargetindex, T_e) * pop * nne; C_ion += C; - globals::cellhistory[tid].cooling_contrib[i] = C_ion; + if constexpr (update_cooling_contrib_list) { + globals::cellhistory[tid].cooling_contrib[i] = C_ion; - assert_testmodeonly(coolinglist[i].type == COOLINGTYPE_FB); - assert_testmodeonly(coolinglist[i].element == element); - assert_testmodeonly(coolinglist[i].ion == ion); - assert_testmodeonly(coolinglist[i].level == level); - assert_testmodeonly(coolinglist[i].upperlevel == get_phixsupperlevel(element, ion, level, phixstargetindex)); + assert_testmodeonly(coolinglist[i].type == COOLINGTYPE_FB); + assert_testmodeonly(coolinglist[i].element == element); + assert_testmodeonly(coolinglist[i].ion == ion); + assert_testmodeonly(coolinglist[i].level == level); + assert_testmodeonly(coolinglist[i].upperlevel == get_phixsupperlevel(element, ion, level, phixstargetindex)); - i++; + i++; + } else { + *C_fb += C; + } } } } - assert_testmodeonly(indexionstart == get_coolinglistoffset(element, ion)); - assert_always(i == indexionstart + get_ncoolingterms(element, ion)); + if constexpr (update_cooling_contrib_list) { + assert_testmodeonly(indexionstart == get_coolinglistoffset(element, ion)); + assert_always(i == indexionstart + get_ncoolingterms_ion(element, ion)); + } + + return C_ion; +} + +void calculate_cooling_rates(const int modelgridindex, struct heatingcoolingrates *heatingcoolingrates) +// Calculate the cooling rates for a given cell and store them for each ion +// optionally store components (ff, bf, collisional) in heatingcoolingrates struct +{ + double C_ff_all = 0.; /// free-free creation of rpkts + double C_fb_all = 0.; /// free-bound creation of rpkt + double C_exc_all = 0.; /// collisional excitation of macroatoms + double C_ionization_all = 0.; /// collisional ionisation of macroatoms + for (int element = 0; element < get_nelements(); element++) { + const int nions = get_nions(element); + for (int ion = 0; ion < nions; ion++) { + const double C_ion = calculate_cooling_rates_ion(modelgridindex, element, ion, -1, tid, &C_ff_all, + &C_fb_all, &C_exc_all, &C_ionization_all); + grid::modelgrid[modelgridindex].cooling_contrib_ion[element][ion] = C_ion; + } + } + + // this loop is made separate for future parallelisation of upper loop. + // the ion contributions must be added in this exact order + double C_total = 0.; + for (int element = 0; element < get_nelements(); element++) { + const int nions = get_nions(element); + for (int ion = 0; ion < nions; ion++) { + C_total += grid::modelgrid[modelgridindex].cooling_contrib_ion[element][ion]; + } + } + grid::modelgrid[modelgridindex].totalcooling = C_total; - // we just summed up every individual cooling process. make sure it matches the stored total for the ion - assert_always(grid::modelgrid[modelgridindex].cooling_contrib_ion[element][ion] == C_ion); + // only used in the T_e solver and write_to_estimators file + if (heatingcoolingrates != nullptr) { + heatingcoolingrates->cooling_collisional = C_exc_all + C_ionization_all; + heatingcoolingrates->cooling_fb = C_fb_all; + heatingcoolingrates->cooling_ff = C_ff_all; + } } static void set_ncoolingterms() { @@ -399,7 +330,7 @@ void setup_coolinglist() { } } } - assert_always(i == get_coolinglistoffset(element, ion) + get_ncoolingterms(element, ion)); + assert_always(i == get_coolinglistoffset(element, ion) + get_ncoolingterms_ion(element, ion)); } } @@ -429,19 +360,16 @@ static auto sample_planck(const double T) -> double } } -auto do_kpkt_bb(struct packet *pkt_ptr) -> double -/// Now routine to deal with a k-packet. Similar idea to do_gamma. +void do_kpkt_blackbody(struct packet *pkt_ptr) +/// handle a k-packet (e.g., in a thick cell) by emitting according to the planck function { - // double nne = globals::cell[pkt_ptr->where].nne ; - const int cellindex = pkt_ptr->where; - const int modelgridindex = grid::get_cell_modelgridindex(cellindex); - const auto T_e = grid::get_Te(modelgridindex); + const int modelgridindex = grid::get_cell_modelgridindex(pkt_ptr->where); - pkt_ptr->nu_cmf = sample_planck(T_e); + pkt_ptr->nu_cmf = sample_planck(grid::get_Te(modelgridindex)); assert_always(std::isfinite(pkt_ptr->nu_cmf)); /// and then emitt the packet randomly in the comoving frame - emitt_rpkt(pkt_ptr); - // printout("[debug] calculate_kappa_rpkt after kpkt to rpkt by ff\n"); + emit_rpkt(pkt_ptr); + // printout("[debug] calculate_chi_rpkt after kpkt to rpkt by ff\n"); pkt_ptr->next_trans = 0; /// FLAG: transition history here not important, cont. process // if (tid == 0) k_stat_to_r_bb++; stats::increment(stats::COUNTER_K_STAT_TO_R_BB); @@ -451,17 +379,14 @@ auto do_kpkt_bb(struct packet *pkt_ptr) -> double vec_copy(pkt_ptr->em_pos, pkt_ptr->pos); pkt_ptr->em_time = pkt_ptr->prop_time; pkt_ptr->nscatterings = 0; - - return pkt_ptr->prop_time; } -auto do_kpkt(struct packet *pkt_ptr, double t2, int nts) -> double -/// Now routine to deal with a k-packet. Similar idea to do_gamma. +void do_kpkt(struct packet *pkt_ptr, double t2, int nts) +/// handle a k-packet (kinetic energy of the free electrons) { const int tid = get_thread_num(); const double t1 = pkt_ptr->prop_time; - const int cellindex = pkt_ptr->where; - const int modelgridindex = grid::get_cell_modelgridindex(cellindex); + const int modelgridindex = grid::get_cell_modelgridindex(pkt_ptr->where); /// don't calculate cooling rates after each cell crossings any longer /// but only if we really get a kpkt and they hadn't been calculated already @@ -471,13 +396,16 @@ auto do_kpkt(struct packet *pkt_ptr, double t2, int nts) -> double const auto T_e = grid::get_Te(modelgridindex); double deltat = 0.; if (nts < globals::n_kpktdiffusion_timesteps) { - deltat = globals::kpktdiffusion_timescale * globals::time_step[nts].width; + deltat = globals::kpktdiffusion_timescale * globals::timesteps[nts].width; } // double deltat = 1. / (nne * 1.02e-12 * pow(T_e / 1e4, 0.843)); // printout("kpkt diffusion time simple %g, advanced %g\n", deltat, 1 / (nne * 1.02e-12 * pow(T_e / 1e4, 0.843))); - double const t_current = t1 + deltat; + const double t_current = t1 + deltat; - if (t_current <= t2) { + if (t_current > t2) { + vec_scale(pkt_ptr->pos, t2 / t1); + pkt_ptr->prop_time = t2; + } else { vec_scale(pkt_ptr->pos, t_current / t1); pkt_ptr->prop_time = t_current; @@ -525,13 +453,16 @@ auto do_kpkt(struct packet *pkt_ptr, double t2, int nts) -> double // printout("element %d, ion %d, coolingsum %g\n",element,ion,coolingsum); const int ilow = get_coolinglistoffset(element, ion); - const int ihigh = ilow + get_ncoolingterms(element, ion) - 1; + const int ihigh = ilow + get_ncoolingterms_ion(element, ion) - 1; // printout("element %d, ion %d, low %d, high %d\n",element,ion,low,high); if (globals::cellhistory[tid].cooling_contrib[ilow] < 0.) { // printout("calculate kpkt rates on demand modelgridindex %d element %d ion %d ilow %d ihigh %d // oldcoolingsum %g\n", // modelgridindex, element, ion, ilow, high, oldcoolingsum); - calculate_kpkt_rates_ion(modelgridindex, element, ion, ilow, tid); + const double C_ion = calculate_cooling_rates_ion(modelgridindex, element, ion, ilow, tid, nullptr, nullptr, + nullptr, nullptr); + // we just summed up every individual cooling process. make sure it matches the stored total for the ion + assert_always(C_ion == grid::modelgrid[modelgridindex].cooling_contrib_ion[element][ion]); } // with the ion selected, we now select a level and transition type @@ -548,12 +479,12 @@ auto do_kpkt(struct packet *pkt_ptr, double t2, int nts) -> double printout("do_kpkt: error occured while selecting a cooling channel: low %d, high %d, i %d, rndcool %g\n", ilow, ihigh, i, rndcool_ion_process); printout("element %d, ion %d, offset %d, terms %d, coolingsum %g\n", element, ion, - get_coolinglistoffset(element, ion), get_ncoolingterms(element, ion), coolingsum); + get_coolinglistoffset(element, ion), get_ncoolingterms_ion(element, ion), coolingsum); printout("lower %g, %g, %g\n", globals::cellhistory[tid].cooling_contrib[get_coolinglistoffset(element, ion) - 1], globals::cellhistory[tid].cooling_contrib[get_coolinglistoffset(element, ion)], globals::cellhistory[tid].cooling_contrib[get_coolinglistoffset(element, ion) + 1]); - int const finalpos = get_coolinglistoffset(element, ion) + get_ncoolingterms(element, ion) - 1; + const int finalpos = get_coolinglistoffset(element, ion) + get_ncoolingterms_ion(element, ion) - 1; printout("upper %g, %g, %g\n", globals::cellhistory[tid].cooling_contrib[finalpos - 1], globals::cellhistory[tid].cooling_contrib[finalpos], globals::cellhistory[tid].cooling_contrib[finalpos + 1]); @@ -577,22 +508,17 @@ auto do_kpkt(struct packet *pkt_ptr, double t2, int nts) -> double assert_always(std::isfinite(pkt_ptr->nu_cmf)); /// and then emitt the packet randomly in the comoving frame - emitt_rpkt(pkt_ptr); + emit_rpkt(pkt_ptr); pkt_ptr->next_trans = 0; /// FLAG: transition history here not important, cont. process stats::increment(stats::COUNTER_K_STAT_TO_R_FF); - pkt_ptr->interactions += 1; pkt_ptr->last_event = 6; pkt_ptr->emissiontype = EMTYPE_FREEFREE; vec_copy(pkt_ptr->em_pos, pkt_ptr->pos); pkt_ptr->em_time = pkt_ptr->prop_time; pkt_ptr->nscatterings = 0; - if constexpr (VPKT_ON) { - // generate a virtual packet - int const realtype = 2; - vpkt_call_estimators(pkt_ptr, t_current, realtype); - } + vpkt_call_estimators(pkt_ptr, TYPE_KPKT); } else if (coolinglist[i].type == COOLINGTYPE_FB) { /// The k-packet converts directly into a r-packet by free-bound-emission. /// Need to select the r-packets frequency and a random direction in the @@ -601,35 +527,29 @@ auto do_kpkt(struct packet *pkt_ptr, double t2, int nts) -> double const int lowerion = coolinglist[i].ion; const int lowerlevel = coolinglist[i].level; const int upper = coolinglist[i].upperlevel; - // const double nu_threshold = get_phixs_threshold(element, ion, lowerlevel, phixstargetindex) /// then randomly sample the packets frequency according to the continuums /// energy distribution // Sample the packets comoving frame frequency according to paperII 4.2.2 - // zrand = rng_uniform(); - // if (zrand < 0.5) - { pkt_ptr->nu_cmf = select_continuum_nu(element, lowerion, lowerlevel, upper, T_e); } - // else - // { - // ///Emitt like a BB + // const double zrand = rng_uniform(); + // if (zrand < 0.5) { + pkt_ptr->nu_cmf = select_continuum_nu(element, lowerion, lowerlevel, upper, T_e); + // } else { + // // Emit like a BB // pkt_ptr->nu_cmf = sample_planck(T_e); // } // and then emitt the packet randomly in the comoving frame - emitt_rpkt(pkt_ptr); + emit_rpkt(pkt_ptr); if constexpr (TRACK_ION_STATS) { stats::increment_ion_stats(modelgridindex, element, lowerion + 1, stats::ION_RADRECOMB_KPKT, pkt_ptr->e_cmf / H / pkt_ptr->nu_cmf); - const double escape_prob = get_rpkt_escape_prob(pkt_ptr, pkt_ptr->prop_time); - stats::increment_ion_stats(modelgridindex, element, lowerion + 1, stats::ION_RADRECOMB_ESCAPED, - pkt_ptr->e_cmf / H / pkt_ptr->nu_cmf * escape_prob); } pkt_ptr->next_trans = 0; /// FLAG: transition history here not important, cont. process stats::increment(stats::COUNTER_K_STAT_TO_R_FB); - pkt_ptr->interactions += 1; pkt_ptr->last_event = 7; pkt_ptr->emissiontype = get_continuumindex(element, lowerion, lowerlevel, upper); pkt_ptr->trueemissiontype = pkt_ptr->emissiontype; @@ -637,11 +557,7 @@ auto do_kpkt(struct packet *pkt_ptr, double t2, int nts) -> double pkt_ptr->em_time = pkt_ptr->prop_time; pkt_ptr->nscatterings = 0; - // call the estimator routine - generate a virtual packet - if constexpr (VPKT_ON) { - int const realtype = 2; - vpkt_call_estimators(pkt_ptr, t_current, realtype); - } + vpkt_call_estimators(pkt_ptr, TYPE_KPKT); } else if (coolinglist[i].type == COOLINGTYPE_COLLEXC) { /// the k-packet activates a macro-atom due to collisional excitation // printout("[debug] do_kpkt: k-pkt -> collisional excitation of MA\n"); @@ -661,8 +577,9 @@ auto do_kpkt(struct packet *pkt_ptr, double t2, int nts) -> double int upper = -1; // excitation to same ionization stage const int nuptrans = get_nuptrans(element, ion, level); + const auto *const uptrans = globals::elements[element].ions[ion].levels[level].uptrans; for (int ii = 0; ii < nuptrans; ii++) { - const int tmpupper = globals::elements[element].ions[ion].levels[level].uptrans[ii].targetlevelindex; + const int tmpupper = uptrans[ii].targetlevelindex; // printout(" excitation to level %d possible\n",upper); const double epsilon_trans = epsilon(element, ion, tmpupper) - epsilon_current; const double C = nnlevel * @@ -702,7 +619,6 @@ auto do_kpkt(struct packet *pkt_ptr, double t2, int nts) -> double stats::increment(stats::COUNTER_MA_STAT_ACTIVATION_COLLEXC); stats::increment(stats::COUNTER_K_STAT_TO_MA_COLLEXC); - pkt_ptr->interactions += 1; pkt_ptr->last_event = 8; pkt_ptr->trueemissiontype = EMTYPE_NOTSET; pkt_ptr->trueemissionvelocity = -1; @@ -725,7 +641,6 @@ auto do_kpkt(struct packet *pkt_ptr, double t2, int nts) -> double stats::increment(stats::COUNTER_MA_STAT_ACTIVATION_COLLION); stats::increment(stats::COUNTER_K_STAT_TO_MA_COLLION); - pkt_ptr->interactions += 1; pkt_ptr->last_event = 9; pkt_ptr->trueemissiontype = EMTYPE_NOTSET; pkt_ptr->trueemissionvelocity = -1; @@ -738,11 +653,8 @@ auto do_kpkt(struct packet *pkt_ptr, double t2, int nts) -> double abort(); } - return pkt_ptr->prop_time; + pkt_ptr->interactions++; } - vec_scale(pkt_ptr->pos, t2 / t1); - pkt_ptr->prop_time = t2; - return pkt_ptr->prop_time; } /*static int compare_coolinglistentry(const void *p1, const void *p2) diff --git a/kpkt.h b/kpkt.h index f8e8861a5..f7f46deda 100644 --- a/kpkt.h +++ b/kpkt.h @@ -11,8 +11,8 @@ namespace kpkt { void setup_coolinglist(); void calculate_cooling_rates(int modelgridindex, struct heatingcoolingrates *heatingcoolingrates); -double do_kpkt_bb(struct packet *pkt_ptr); -double do_kpkt(struct packet *pkt_ptr, double t2, int nts); +void do_kpkt_blackbody(struct packet *pkt_ptr); +void do_kpkt(struct packet *pkt_ptr, double t2, int nts); static inline int get_coolinglistoffset(int element, int ion) { return globals::elements[element].ions[ion].coolingoffset; diff --git a/light_curve.cc b/light_curve.cc index 7a41c374d..bb2bdb1ee 100644 --- a/light_curve.cc +++ b/light_curve.cc @@ -6,9 +6,10 @@ // Routine to make a MC light curve from the r-packets. -void write_light_curve(const std::string &lc_filename, const int current_abin, const double *light_curve_lum, - const double *light_curve_lumcmf, const int numtimesteps) { - assert_always(numtimesteps <= globals::ntstep); +void write_light_curve(const std::string &lc_filename, const int current_abin, + const std::vector &light_curve_lum, const std::vector &light_curve_lumcmf, + const int numtimesteps) { + assert_always(numtimesteps <= globals::ntimesteps); std::ofstream lc_file(lc_filename); if (!lc_file) { @@ -22,7 +23,7 @@ void write_light_curve(const std::string &lc_filename, const int current_abin, c /// Print out the UVOIR bolometric light curve. for (int nts = 0; nts < numtimesteps; nts++) { - assert_always(snprintf(linebuffer, maxlen, "%g %g %g", globals::time_step[nts].mid / DAY, + assert_always(snprintf(linebuffer, maxlen, "%g %g %g", globals::timesteps[nts].mid / DAY, (light_curve_lum[nts] / LSUN), (light_curve_lumcmf[nts] / LSUN)) < maxlen); lc_file << linebuffer << '\n'; } @@ -30,15 +31,16 @@ void write_light_curve(const std::string &lc_filename, const int current_abin, c if (current_abin == -1) { /// Now print out the gamma ray deposition rate in the same file. for (int m = 0; m < numtimesteps; m++) { - assert_always(snprintf(linebuffer, maxlen, "%g %g %g", globals::time_step[m].mid / DAY, - (globals::time_step[m].gamma_dep / LSUN / globals::time_step[m].width), - (globals::time_step[m].cmf_lum / globals::time_step[m].width / LSUN)) < maxlen); + assert_always(snprintf(linebuffer, maxlen, "%g %g %g", globals::timesteps[m].mid / DAY, + (globals::timesteps[m].gamma_dep / LSUN / globals::timesteps[m].width), + (globals::timesteps[m].cmf_lum / globals::timesteps[m].width / LSUN)) < maxlen); lc_file << linebuffer << '\n'; } } } -void add_to_lc_res(const struct packet *pkt_ptr, int current_abin, double *light_curve_lum, double *light_curve_lumcmf) +void add_to_lc_res(const struct packet *pkt_ptr, int current_abin, std::vector &light_curve_lum, + std::vector &light_curve_lumcmf) // add a packet to the outgoing light-curve. { if (current_abin == -1) { @@ -46,7 +48,7 @@ void add_to_lc_res(const struct packet *pkt_ptr, int current_abin, double *light const double arrive_time = get_arrive_time(pkt_ptr); if (arrive_time > globals::tmin && arrive_time < globals::tmax) { const int nt = get_timestep(arrive_time); - safeadd(light_curve_lum[nt], pkt_ptr->e_rf / globals::time_step[nt].width / globals::nprocs); + safeadd(light_curve_lum[nt], pkt_ptr->e_rf / globals::timesteps[nt].width / globals::nprocs_exspec); } /// Now do the cmf light curve. @@ -54,7 +56,7 @@ void add_to_lc_res(const struct packet *pkt_ptr, int current_abin, double *light const double arrive_time_cmf = get_arrive_time_cmf(pkt_ptr); if (arrive_time_cmf > globals::tmin && arrive_time_cmf < globals::tmax) { const int nt = get_timestep(arrive_time_cmf); - safeadd(light_curve_lumcmf[nt], pkt_ptr->e_cmf / globals::time_step[nt].width / globals::nprocs / + safeadd(light_curve_lumcmf[nt], pkt_ptr->e_cmf / globals::timesteps[nt].width / globals::nprocs_exspec / sqrt(1. - (globals::vmax * globals::vmax / CLIGHTSQUARED))); } @@ -62,10 +64,10 @@ void add_to_lc_res(const struct packet *pkt_ptr, int current_abin, double *light } if (get_escapedirectionbin(pkt_ptr->dir, globals::syn_dir) == current_abin) { // Add only packets which escape to the current angle bin - double const t_arrive = get_arrive_time(pkt_ptr); + const double t_arrive = get_arrive_time(pkt_ptr); if (t_arrive > globals::tmin && t_arrive < globals::tmax) { - int const nt = get_timestep(t_arrive); - safeadd(light_curve_lum[nt], pkt_ptr->e_rf / globals::time_step[nt].width * MABINS / globals::nprocs); + const int nt = get_timestep(t_arrive); + safeadd(light_curve_lum[nt], pkt_ptr->e_rf / globals::timesteps[nt].width * MABINS / globals::nprocs_exspec); } } } \ No newline at end of file diff --git a/light_curve.h b/light_curve.h index 46c2c2647..b2cc4d5bc 100644 --- a/light_curve.h +++ b/light_curve.h @@ -2,12 +2,14 @@ #define LIGHT_CURVE_H #include +#include #include "exspec.h" -void add_to_lc_res(const struct packet *pkt_ptr, int current_abin, double *light_curve_lum, double *light_curve_lumcmf); +void add_to_lc_res(const struct packet *pkt_ptr, int current_abin, std::vector &light_curve_lum, + std::vector &light_curve_lumcmf); -void write_light_curve(const std::string &lc_filename, int current_abin, const double *light_curve_lum, - const double *light_curve_lumcmf, int numtimesteps); +void write_light_curve(const std::string &lc_filename, int current_abin, const std::vector &light_curve_lum, + const std::vector &light_curve_lumcmf, int numtimesteps); #endif // LIGHT_CURVE_H diff --git a/ltepop.cc b/ltepop.cc index 5891c1c7b..c9dae7f07 100644 --- a/ltepop.cc +++ b/ltepop.cc @@ -1,5 +1,8 @@ #include "ltepop.h" +#include +#include + #include #include @@ -13,101 +16,41 @@ #include "sn3d.h" #include "update_grid.h" -auto nne_solution_f(double x, void *paras) -> double -/// For libgsl bracketing type solver -/// provides the equation which has to be solved to obtain the electron number -/// density (passed by x) -{ - const int modelgridindex = (static_cast(paras))->cellnumber; - const double rho = grid::get_rho(modelgridindex); - - double outersum = 0.; - // printout("debug get_nelements() %d =========================\n",get_nelements()); - for (int element = 0; element < get_nelements(); element++) { - const double abundance = grid::modelgrid[modelgridindex].composition[element].abundance; - if (abundance > 0 && get_nions(element) > 0) { - const double elem_meanweight = grid::get_element_meanweight(modelgridindex, element); - double innersum = 0.; - // printout("debug get_nions (element %d) %d =========================\n",element,get_nions(element)); - // uppermost_ion = globals::elements[element].uppermost_ion; - const int uppermost_ion = grid::get_elements_uppermost_ion(modelgridindex, element); - - auto ionfractions = std::make_unique(uppermost_ion + 1); - get_ionfractions(element, modelgridindex, x, ionfractions.get(), uppermost_ion); - - int ion = 0; - for (ion = 0; ion <= uppermost_ion; ion++) { - // printout("debug element %d, ion %d, ionfract(element,ion,T,x) %g\n",element,ion,ionfractions[ion]); - innersum += (get_ionstage(element, ion) - 1) * ionfractions[ion]; - } - assert_always(std::isfinite(innersum)); - outersum += abundance / elem_meanweight * innersum; - if (!std::isfinite(outersum)) { - printout("nne_solution_f: element %d ion %d uppermostion %d abundance %g, mass %g\n", element, ion, - grid::get_elements_uppermost_ion(modelgridindex, element), abundance, elem_meanweight); - printout("outersum %g\n", outersum); - abort(); - } - } - } - - return rho * outersum - x; -} - -void get_ionfractions(int element, int modelgridindex, double nne, double *ionfractions, int uppermost_ion) -// Calculate the fractions of an element's population in each ionization stage -// size of ionfractions array must be >= uppermostion + 1 -{ - assert_testmodeonly(modelgridindex < grid::get_npts_model()); - assert_testmodeonly(element < get_nelements()); - assert_testmodeonly(uppermost_ion < get_nions(element) || get_nions(element) == 0); - - auto nnionfactor = std::make_unique(uppermost_ion + 1); - nnionfactor[uppermost_ion] = 1; - - double denominator = 1.; - - for (int ion = uppermost_ion - 1; ion >= 0; ion--) { - nnionfactor[ion] = nnionfactor[ion + 1] * nne * phi(element, ion, modelgridindex); - denominator += nnionfactor[ion]; - } - - for (int ion = 0; ion <= uppermost_ion; ion++) { - const double numerator = nnionfactor[ion]; - ionfractions[ion] = numerator / denominator; - - if (!std::isfinite(ionfractions[ion])) { - if (modelgridindex != grid::get_npts_model()) { - printout("[warning] ionfract set to zero for ionstage %d of Z=%d in cell %d with T_e %g, T_R %g\n", - get_ionstage(element, ion), get_atomicnumber(element), modelgridindex, grid::get_Te(modelgridindex), - grid::get_TR(modelgridindex)); - // abort(); - ionfractions[ion] = 0; - } - } - // printout("ionfract(%d,%d,%d,%g) = %g\n", element, ion, modelgridindex, nne, ionfractions[ion]); - } -} +struct nne_solution_paras { + int modelgridindex; + bool force_lte; +}; static auto interpolate_ions_spontrecombcoeff(const int element, const int ion, const double T) -> double { assert_testmodeonly(element < get_nelements()); assert_testmodeonly(ion < get_nions(element)); assert_always(T >= MINTEMP); - int const lowerindex = floor(log(T / MINTEMP) / T_step_log); + const int lowerindex = floor(log(T / MINTEMP) / T_step_log); if (lowerindex < TABLESIZE - 1) { - int const upperindex = lowerindex + 1; - double const T_lower = MINTEMP * exp(lowerindex * T_step_log); - double const T_upper = MINTEMP * exp(upperindex * T_step_log); + const int upperindex = lowerindex + 1; + const double T_lower = MINTEMP * exp(lowerindex * T_step_log); + const double T_upper = MINTEMP * exp(upperindex * T_step_log); - double const f_upper = globals::elements[element].ions[ion].Alpha_sp[upperindex]; - double const f_lower = globals::elements[element].ions[ion].Alpha_sp[lowerindex]; + const double f_upper = globals::elements[element].ions[ion].Alpha_sp[upperindex]; + const double f_lower = globals::elements[element].ions[ion].Alpha_sp[lowerindex]; return f_lower + (f_upper - f_lower) / (T_upper - T_lower) * (T - T_lower); } return globals::elements[element].ions[ion].Alpha_sp[TABLESIZE - 1]; } -auto phi(const int element, const int ion, const int modelgridindex) -> double +static auto phi_lte(const int element, const int ion, const int modelgridindex) -> double { + // use Saha equation for LTE ionization balance + auto partfunc_ion = grid::modelgrid[modelgridindex].composition[element].partfunct[ion]; + auto partfunc_upperion = grid::modelgrid[modelgridindex].composition[element].partfunct[ion + 1]; + + const auto T_e = grid::get_Te(modelgridindex); + const double ionpot = epsilon(element, ion + 1, 0) - epsilon(element, ion, 0); + const double partfunct_ratio = partfunc_ion / partfunc_upperion; + return partfunct_ratio * SAHACONST * pow(T_e, -1.5) * exp(ionpot / KB / T_e); +} + +static auto phi_ion_equilib(const int element, const int ion, const int modelgridindex) -> double /// Calculates population ratio (a saha factor) of two consecutive ionisation stages /// in nebular approximation phi_j,k* = N_j,k*/(N_j+1,k* * nne) { @@ -115,185 +58,151 @@ auto phi(const int element, const int ion, const int modelgridindex) -> double assert_testmodeonly(element < get_nelements()); assert_testmodeonly(ion < get_nions(element)); - double phi = 0; + assert_testmodeonly(!globals::lte_iteration); + assert_testmodeonly(grid::modelgrid[modelgridindex].thick != 1); // should use use phi_lte instead - // double Y_nt, ionpot_in; - // int element_in, ion_in, nions_in; - // double rate_use; + assert_testmodeonly(!elem_has_nlte_levels(element)); // don't use this function if the NLTE solver is active + + auto partfunc_ion = grid::modelgrid[modelgridindex].composition[element].partfunct[ion]; + auto partfunc_upperion = grid::modelgrid[modelgridindex].composition[element].partfunct[ion + 1]; const auto T_e = grid::get_Te(modelgridindex); - // double T_R = grid::get_TR(modelgridindex); - - // double W = globals::cell[cellnumber].W; - - /// Old ionisation formula - // partfunct_ratio = - // globals::cell[cellnumber].composition[element].partfunct[ion]/globals::cell[cellnumber].composition[element].partfunct[ion+1]; - // phi = 1./W * sqrt(T_R/T_e) * partfunct_ratio * SAHACONST * pow(T_R,-1.5) * exp(ionpot/KB/T_R); - - /// New ionisation formula with zeta - // zeta = interpolate_zeta(element,ion,T_e); - // phi = 1./W * 1./(zeta+W*(1-zeta)) * sqrt(T_R/T_e) * partfunct_ratio * SAHACONST * pow(T_R,-1.5) * - // exp(ionpot/KB/T_R); - - /// Newest ionisation formula - - const bool use_lte_ratio = (globals::initial_iteration || grid::modelgrid[modelgridindex].thick == 1); - - if (use_lte_ratio) { - const double ionpot = epsilon(element, ion + 1, 0) - epsilon(element, ion, 0); - // printout("ionpot for element %d, ion %d is %g\n", element, ion, ionpot / EV); - const double partfunct_ratio = grid::modelgrid[modelgridindex].composition[element].partfunct[ion] / - grid::modelgrid[modelgridindex].composition[element].partfunct[ion + 1]; - phi = partfunct_ratio * SAHACONST * pow(T_e, -1.5) * exp(ionpot / KB / T_e); - } else - // elseif (NLTE_POPS_ALL_IONS_SIMULTANEOUS) - // { - // const float nne = grid::get_nne(modelgridindex); - // phi = ionstagepop(modelgridindex,element,ion) / ionstagepop(modelgridindex,element,ion+1) / nne; - // } - // else - { - double Gamma = 0.; - if constexpr (!USE_LUT_PHOTOION) { - Gamma = calculate_iongamma_per_gspop(modelgridindex, element, ion); - } else { - Gamma = - globals::gammaestimator[modelgridindex * get_nelements() * get_max_nions() + element * get_max_nions() + ion]; - } - // printout("phicompare element %d ion %d T_e = %g gammaestimator %g calculate_iongamma_per_gspop %g\n", - // element, ion, T_e, - // globals::gammaestimator[modelgridindex * get_nelements() * get_max_nions() + element * get_max_nions() + - // ion], calculate_iongamma_per_gspop(modelgridindex, element, ion)); - - // Gamma is the photoionization rate per ground level pop - const double Gamma_ion = - Gamma * stat_weight(element, ion, 0) / grid::modelgrid[modelgridindex].composition[element].partfunct[ion]; - - if (Gamma == 0. && (!NT_ON || (globals::rpkt_emiss[modelgridindex] == 0. && - grid::get_modelinitradioabund(modelgridindex, decay::get_nucindex(24, 48)) == 0. && - grid::get_modelinitradioabund(modelgridindex, decay::get_nucindex(28, 56)) == 0.))) { - printout("Fatal: Gamma = 0 for element %d, ion %d in phi ... abort\n", element, ion); - abort(); - } - // Alpha_st = stimrecombestimator[cellnumber*get_nelements()*get_max_nions()+element*get_max_nions()+ion]; - double const Alpha_st = 0.; /// approximate treatment neglects stimulated recombination + double Gamma = 0.; + if constexpr (USE_LUT_PHOTOION) { + Gamma = globals::gammaestimator[get_ionestimindex(modelgridindex, element, ion)]; + } else { + Gamma = calculate_iongamma_per_gspop(modelgridindex, element, ion); + } - double Alpha_sp = 0.; - if constexpr (NLTE_POPS_ON) { - Alpha_sp = - calculate_ionrecombcoeff(modelgridindex, T_e, element, ion + 1, false, false, false, false, false, false); - } else { - Alpha_sp = interpolate_ions_spontrecombcoeff(element, ion, T_e); - } + // Gamma is the photoionization rate per ground level pop + const double Gamma_ion = Gamma * stat_weight(element, ion, 0) / partfunc_ion; - // const double Col_rec = calculate_ionrecombcoeff(modelgridindex, T_e, element, ion + 1, false, true, false, false, - // false); - const double Col_rec = 0.; + if (Gamma == 0. && (!NT_ON || (globals::rpkt_emiss[modelgridindex] == 0. && + grid::get_modelinitradioabund(modelgridindex, decay::get_nucindex(24, 48)) == 0. && + grid::get_modelinitradioabund(modelgridindex, decay::get_nucindex(28, 56)) == 0.))) { + printout("Fatal: Gamma = 0 for element %d, ion %d in phi ... abort\n", element, ion); + abort(); + } - double Y_nt = 0.0; + const double Alpha_sp = interpolate_ions_spontrecombcoeff(element, ion, T_e); - if constexpr (NT_ON) { - Y_nt = nonthermal::nt_ionization_ratecoeff(modelgridindex, element, ion); - } + // const double Col_rec = calculate_ionrecombcoeff(modelgridindex, T_e, element, ion + 1, false, true, false, false, + // false); + const double Col_rec = 0.; - // || !std::isfinite(Gamma)) - // return phi_lte(element,ion,cellnumber); - // gamma_lte = interpolate_photoioncoeff_below(element,ion,0,T_e) + - // interpolate_photoioncoeff_above(element,ion,0,T_e); zeta = interpolate_zeta(element,ion,T_e); alpha_sp = - // interpolate_spontrecombcoeff(element,ion,0,T_e); phi = gamma_lte*(Alpha_sp+Apha_st)/(Gamma*alpha_sp) * - // partfunct_ratio * SAHACONST * pow(T_e,-1.5) * exp(ionpot/KB/T_e); + const double gamma_nt = NT_ON ? nonthermal::nt_ionization_ratecoeff(modelgridindex, element, ion) : 0.; - phi = (Alpha_sp + Alpha_st + Col_rec) / (Gamma_ion + Y_nt); + const double phi = (Alpha_sp + Col_rec) / (Gamma_ion + gamma_nt); - // Y_nt should generally be higher than the Gamma term for nebular epoch + // Y_nt should generally be higher than the Gamma term for nebular epoch - if (!std::isfinite(phi) || phi == 0.) { - printout( - "[fatal] phi: phi %g exceeds numerically possible range for element %d, ion %d, T_e %g ... remove higher or " - "lower ionisation stages\n", - phi, element, ion, T_e); - printout("[fatal] phi: Alpha_sp %g, Alpha_st %g, Gamma %g, partfunct %g, stat_weight %g\n", Alpha_sp, Alpha_st, - Gamma, grid::modelgrid[modelgridindex].composition[element].partfunct[ion], - stat_weight(element, ion, 0)); - printout("[fatal] phi: upperionpartfunct %g, upperionstatweight %g\n", - grid::modelgrid[modelgridindex].composition[element].partfunct[ion + 1], - stat_weight(element, ion + 1, 0)); - printout("[fatal] phi: Y_nt %g Col_rec %g grid::get_nne(modelgridindex) %g\n", Y_nt, Col_rec, - grid::get_nne(modelgridindex)); - // abort(); - } + if (!std::isfinite(phi) || phi == 0.) { + printout( + "[fatal] phi: phi %g exceeds numerically possible range for element %d, ion %d, T_e %g ... remove higher or " + "lower ionisation stages\n", + phi, element, ion, T_e); + printout("[fatal] phi: Alpha_sp %g, Gamma %g, partfunct %g, stat_weight %g\n", Alpha_sp, Gamma, partfunc_ion, + stat_weight(element, ion, 0)); + printout("[fatal] phi: upperionpartfunct %g, upperionstatweight %g\n", partfunc_upperion, + stat_weight(element, ion + 1, 0)); + printout("[fatal] phi: gamma_nt %g Col_rec %g grid::get_nne(modelgridindex) %g\n", gamma_nt, Col_rec, + grid::get_nne(modelgridindex)); + abort(); } return phi; } -// double phi_lte(int element, int ion, int cellnumber) -/// Calculates population ratio (a saha factor) of two consecutive ionisation stages -/// in nebular approximation phi_j,k* = N_j,k*/N_j+1,k* * nne -/*{ - double partfunct_ratio; - double phi; +[[nodiscard]] auto calculate_ionfractions(const int element, const int modelgridindex, const double nne, + const bool use_phi_lte) -> std::vector +// Calculate the fractions of an element's population in each ionization stage based on Saha LTE or ionisation +// equilibrium +{ + const int uppermost_ion = grid::get_elements_uppermost_ion(modelgridindex, element); + assert_testmodeonly(modelgridindex < grid::get_npts_model()); + assert_testmodeonly(element < get_nelements()); + assert_testmodeonly(uppermost_ion <= std::max(0, get_nions(element) - 1)); - double ionpot = epsilon(element,ion+1,0) - epsilon(element,ion,0); - float T_e = globals::cell[cellnumber].T_e; + if (uppermost_ion < 0) { + return {}; + } + + std::vector ionfractions(uppermost_ion + 1); + ionfractions[uppermost_ion] = 1; - partfunct_ratio = -globals::cell[cellnumber].composition[element].partfunct[ion]/globals::cell[cellnumber].composition[element].partfunct[ion+1]; - phi = partfunct_ratio * SAHACONST * pow(T_e,-1.5) * exp(ionpot/KB/T_e); + double normfactor = 1.; - if (!std::isfinite(phi)) - { - printout("phi_lte: phi %g exceeds numerically possible range for element %d, ion %d, T_e %g, ... remove higher or -lower ionisation stages\n",phi,element,ion,T_e); abort(); + for (int ion = uppermost_ion - 1; ion >= 0; ion--) { + const auto phifactor = + use_phi_lte ? phi_lte(element, ion, modelgridindex) : phi_ion_equilib(element, ion, modelgridindex); + ionfractions[ion] = ionfractions[ion + 1] * nne * phifactor; + normfactor += ionfractions[ion]; } - return phi; -}*/ -/* -double calculate_ltepartfunct(int element, int ion, double T) -/// Calculates the LTE partition function for ion=ion of element=element at -/// temperature T -{ - double U; - double epsilon_groundlevel; - double oneoverkbt; - int level; - int nlevels; - - epsilon_groundlevel = epsilon(element,ion,0); - oneoverkbt = 1/KB/T; - U = 0.; - nlevels = get_nlevels(element,ion); - for (level = 0; level < nlevels; level++) - { - U += stat_weight(element,ion,level) * exp(-(epsilon(element,ion,level)-epsilon_groundlevel)*oneoverkbt); - } - - if (!std::isfinite(U)) abort(); - return U; + for (int ion = 0; ion <= uppermost_ion; ion++) { + ionfractions[ion] = ionfractions[ion] / normfactor; + + if (!std::isfinite(ionfractions[ion]) && modelgridindex != grid::get_npts_model()) { + printout("[warning] ionfract set to zero for ionstage %d of Z=%d in cell %d with T_e %g, T_R %g\n", + get_ionstage(element, ion), get_atomicnumber(element), modelgridindex, grid::get_Te(modelgridindex), + grid::get_TR(modelgridindex)); + ionfractions[ion] = 0; + } + } + return ionfractions; +} + +static auto get_element_nne_contrib(const int modelgridindex, const int element) + -> double { // calculate number density of the current element (abundances are given by mass) + const double nnelement = grid::get_elem_numberdens(modelgridindex, element); + // Use ionization fractions to calculate the free electron contributions + if (nnelement > 0) { + double nne = 0.; + const int nions = get_nions(element); + for (int ion = 0; ion < nions; ion++) { + const auto nnion = get_nnion(modelgridindex, element, ion); + const int ioncharge = get_ionstage(element, ion) - 1; + nne += ioncharge * nnion; + } + return nne; + } + return 0.; } -*/ -/* -double calculate_groundlevelpop(int element, int ion, double T, int cellnumber, double nne, double nnnextion) -///calculates ground level population for ion=ion of element=element at -///temperature T and electron number density nne -///further the total population number nnnextion of the next higher ionisation stage is needed +static auto nne_solution_f(double nne_assumed, void *voidparas) -> double +// assume a value for nne and then calculate the resulting nne +// the difference between the assumed and calculated nne is returned { - double partfunct(int element, int ion, double T); + const auto *paras = reinterpret_cast(voidparas); + const int modelgridindex = paras->modelgridindex; + const bool force_lte = paras->force_lte; - double deltaE = epsilon(element,ion+1,0) - epsilon(element,ion,0); - double n0; + double nne_after = 0.; // the resulting nne after setting the ion balance with nne_assumed + for (int element = 0; element < get_nelements(); element++) { + const double nnelement = grid::get_elem_numberdens(modelgridindex, element); + if (nnelement > 0 && get_nions(element) > 0) { + if (!force_lte && elem_has_nlte_levels(element)) { + // populations from the NLTE solver are fixed during the nne solver + nne_after += get_element_nne_contrib(modelgridindex, element); + } else { + const bool use_phi_lte = force_lte || FORCE_SAHA_ION_BALANCE(get_atomicnumber(element)); + const auto ionfractions = calculate_ionfractions(element, modelgridindex, nne_assumed, use_phi_lte); + const int uppermost_ion = static_cast(ionfractions.size() - 1); + for (int ion = 0; ion <= uppermost_ion; ion++) { + const double nnion = nnelement * ionfractions[ion]; + const int ioncharge = get_ionstage(element, ion) - 1; + nne_after += ioncharge * nnion; + } + } - //n0 = nnnextion * nne * stat_weight(element,ion,0)/partfunct(element,ion+1,T) * C * pow(T,-1.5) * exp(deltaE/KB/T); - n0 = nnnextion * nne * stat_weight(element,ion,0)/globals::cell[cellnumber].composition[element].partfunct[ion+1] * -SAHACONST * pow(T,-1.5) * exp(deltaE/KB/T); + assert_always(std::isfinite(nne_after)); + } + } + nne_after = std::max(MINPOP, nne_after); - return n0; + return nne_after - nne_assumed; } -*/ auto get_groundlevelpop(int modelgridindex, int element, int ion) -> double /// Returns the given ions groundlevel population for modelgridindex which was precalculated @@ -302,9 +211,6 @@ auto get_groundlevelpop(int modelgridindex, int element, int ion) -> double assert_testmodeonly(modelgridindex < grid::get_npts_model()); assert_testmodeonly(element < get_nelements()); assert_testmodeonly(ion < get_nions(element)); - // double nn = grid::modelgrid[modelgridindex].composition[element].groundlevelpop[ion]; - // if (nn < MINPOP) nn = MINPOP; - // return nn; const double nn = grid::modelgrid[modelgridindex].composition[element].groundlevelpop[ion]; if (nn < MINPOP) { @@ -323,19 +229,18 @@ auto calculate_levelpop_lte(int modelgridindex, int element, int ion, int level) assert_testmodeonly(element < get_nelements()); assert_testmodeonly(ion < get_nions(element)); assert_testmodeonly(level < get_nlevels(element, ion)); + + const auto nnground = get_groundlevelpop(modelgridindex, element, ion); if (level == 0) { - return get_groundlevelpop(modelgridindex, element, ion); + return nnground; } - const double T_exc = LTEPOP_EXCITATION_USE_TJ ? grid::get_TJ(modelgridindex) : grid::get_Te(modelgridindex); - const double W = 1.; + const auto T_exc = LTEPOP_EXCITATION_USE_TJ ? grid::get_TJ(modelgridindex) : grid::get_Te(modelgridindex); - const double E_level = epsilon(element, ion, level); - const double E_ground = epsilon(element, ion, 0); - const double nnground = get_groundlevelpop(modelgridindex, element, ion); + const double E_aboveground = epsilon(element, ion, level) - epsilon(element, ion, 0); - return (nnground * W * stat_weight(element, ion, level) / stat_weight(element, ion, 0) * - exp(-(E_level - E_ground) / KB / T_exc)); + return (nnground * stat_weight(element, ion, level) / stat_weight(element, ion, 0) * + exp(-E_aboveground / KB / T_exc)); } static auto calculate_levelpop_nominpop(int modelgridindex, int element, int ion, int level, bool *skipminpop) @@ -347,13 +252,10 @@ static auto calculate_levelpop_nominpop(int modelgridindex, int element, int ion double nn = NAN; - // T_exc = MINTEMP; - if (level == 0) { nn = get_groundlevelpop(modelgridindex, element, ion); - } else if constexpr (NLTE_POPS_ON) { + } else if (elem_has_nlte_levels(element)) { if (is_nlte(element, ion, level)) { - // printout("Using an nlte population!\n"); const double nltepop_over_rho = grid::modelgrid[modelgridindex].nlte_pops[globals::elements[element].ions[ion].first_nlte + level - 1]; if (nltepop_over_rho < -0.9) { @@ -372,8 +274,8 @@ static auto calculate_levelpop_nominpop(int modelgridindex, int element, int ion *skipminpop = true; return nn; } - } else // level is in the superlevel - { + } else { + // level is in the superlevel assert_testmodeonly(level_isinsuperlevel(element, ion, level)); const int sl_nlte_index = globals::elements[element].ions[ion].first_nlte + get_nlevels_nlte(element, ion); @@ -412,7 +314,6 @@ auto calculate_levelpop(int modelgridindex, int element, int ion, int level) -> if (!skipminpop && nn < MINPOP) { if (grid::get_elem_abundance(modelgridindex, element) > 0) { nn = MINPOP; - // nn = calculate_levelpop_lte(modelgridindex, element, ion, level); } else { nn = 0.; } @@ -438,7 +339,7 @@ auto get_levelpop(int modelgridindex, int element, int ion, int level) -> double return nn; } -auto calculate_partfunct(int element, int ion, int modelgridindex) -> double +static auto calculate_partfunct(int element, int ion, int modelgridindex) -> double /// Calculates the partition function for ion=ion of element=element in /// cell modelgridindex { @@ -448,18 +349,16 @@ auto calculate_partfunct(int element, int ion, int modelgridindex) -> double double pop_store = NAN; // double E_level, E_ground, test; - int initial = 0; + bool initial = false; if (get_groundlevelpop(modelgridindex, element, ion) < MINPOP) { // either there reall is none of this ion or this is a first pass through // in either case, we won't have any real nlte_populations so the actual value of // of groundlevelpop for this calculation doesn't matter, so long as it's not zero! pop_store = get_groundlevelpop(modelgridindex, element, ion); - initial = 1; + initial = true; grid::modelgrid[modelgridindex].composition[element].groundlevelpop[ion] = 1.0; } - // printout("groundlevelpop %g\n", get_groundlevelpop(modelgridindex,element,ion)); - double U = 1.; const int nlevels = get_nlevels(element, ion); @@ -467,7 +366,6 @@ auto calculate_partfunct(int element, int ion, int modelgridindex) -> double for (int level = 1; level < nlevels; level++) { bool skipminpop = false; const double nn = calculate_levelpop_nominpop(modelgridindex, element, ion, level, &skipminpop) / groundpop; - // const double nn = get_levelpop(modelgridindex, element, ion, level) / groundpop; U += nn; } U *= stat_weight(element, ion, 0); @@ -480,7 +378,7 @@ auto calculate_partfunct(int element, int ion, int modelgridindex) -> double abort(); } - if (initial == 1) { + if (initial) { // put back the zero, just in case it matters for something grid::modelgrid[modelgridindex].composition[element].groundlevelpop[ion] = pop_store; } @@ -488,6 +386,21 @@ auto calculate_partfunct(int element, int ion, int modelgridindex) -> double return U; } +void calculate_cellpartfuncts(const int modelgridindex, const int element) +/// The partition functions depend only on T_R and W. This means they don't +/// change during any iteration on T_e. Therefore their precalculation was +/// taken out of calculate_ion_balance_nne to save runtime. +// TODO: not true if LTEPOP_EXCITATION_USE_TJ is true unless LTE mode only (TJ=TR=Te) +{ + /// Precalculate partition functions for each ion in every cell + /// this saves a factor 10 in calculation time of Saha-Boltzman populations + const int nions = get_nions(element); + for (int ion = 0; ion < nions; ion++) { + grid::modelgrid[modelgridindex].composition[element].partfunct[ion] = + calculate_partfunct(element, ion, modelgridindex); + } +} + auto calculate_sahafact(int element, int ion, int level, int upperionlevel, double T, double E_threshold) -> double /// calculates saha factor in LTE: Phi_level,ion,element = nn_level,ion,element/(nne*nn_upper,ion+1,element) { @@ -498,18 +411,235 @@ auto calculate_sahafact(int element, int ion, int level, int upperionlevel, doub // E_threshold, sf,stat_weight(element,ion,level),stat_weight(element,ion+1,0) ); if (sf < 0) { printout( - "[fatal] calculate_sahafact: Negative Saha factor. sfac %g element %d ion %d level %d upperionlevel %d g_lower " - "%g g_upper %g T %g E_threshold %g exppart %g\n", + "[fatal] calculate_sahafact: Negative Saha factor. sfac %g element %d ion %d level %d upperionlevel %d " + "g_lower %g g_upper %g T %g E_threshold %g exppart %g\n", sf, element, ion, level, upperionlevel, g_lower, g_upper, T, E_threshold, exp(E_threshold / KB / T)); abort(); } return sf; } -auto ionstagepop(int modelgridindex, int element, int ion) -> double -/// Calculates the given ionstages total population in nebular approximation for modelgridindex -/// The precalculated ground level population and partition function are used. +auto get_nnion(int modelgridindex, int element, int ion) -> double +/// Use the ground level population and partition function to get an ion population { return get_groundlevelpop(modelgridindex, element, ion) * grid::modelgrid[modelgridindex].composition[element].partfunct[ion] / stat_weight(element, ion, 0); } + +static auto find_uppermost_ion(const int modelgridindex, const int element, const double nne_hi, const bool force_lte) + -> int { + const int nions = get_nions(element); + if (nions == 0) { + return -1; + } + if (!force_lte && elem_has_nlte_levels(element)) { + return nions - 1; + } + + const bool use_lte = force_lte || FORCE_SAHA_ION_BALANCE(get_atomicnumber(element)); + int uppermost_ion = 0; + + if (force_lte) { + uppermost_ion = nions - 1; + } else { + int ion = -1; + for (ion = 0; ion < nions - 1; ion++) { + if (iongamma_is_zero(modelgridindex, element, ion) && + (!NT_ON || ((globals::rpkt_emiss[modelgridindex] == 0.) && + (grid::get_modelinitradioabund(modelgridindex, decay::get_nucindex(24, 48)) == 0.) && + (grid::get_modelinitradioabund(modelgridindex, decay::get_nucindex(28, 56)) == 0.)))) { + break; + } + } + uppermost_ion = ion; + } + + double factor = 1.; + int ion = 0; + for (ion = 0; ion < uppermost_ion; ion++) { + const auto phifactor = + use_lte ? phi_lte(element, ion, modelgridindex) : phi_ion_equilib(element, ion, modelgridindex); + factor *= nne_hi * phifactor; + + if (!std::isfinite(factor)) { + printout( + "[info] calculate_ion_balance_nne: uppermost_ion limited by phi factors for element " + "Z=%d, ionstage %d in cell %d\n", + get_atomicnumber(element), get_ionstage(element, ion), modelgridindex); + return ion; + } + } + uppermost_ion = ion; + return uppermost_ion; +} + +static void set_calculated_nne(const int modelgridindex) { + double nne = 0.; // free electron density + + for (int element = 0; element < get_nelements(); element++) { + nne += get_element_nne_contrib(modelgridindex, element); + } + + grid::set_nne(modelgridindex, std::max(MINPOP, nne)); +} + +void set_groundlevelpops(const int modelgridindex, const int element, const float nne, const bool force_lte) { + /// If not already set by the NLTE solver, set the ground level populations from either Saha LTE or + /// ionization/recombination balance (Photoionization Equilibrium) + const int nions = get_nions(element); + + if (nions <= 0) { + return; + } + + /// calculate number density of the current element (abundances are given by mass) + const double nnelement = grid::get_elem_numberdens(modelgridindex, element); + + const auto ionfractions = + (nnelement > 0) ? calculate_ionfractions(element, modelgridindex, nne, force_lte) : std::vector(); + + const int uppermost_ion = static_cast(ionfractions.size() - 1); + + /// Use ion fractions to calculate the groundlevel populations + for (int ion = 0; ion < nions; ion++) { + double nnion = NAN; + if (ion <= uppermost_ion) { + if (nnelement > 0) { + nnion = std::max(MINPOP, nnelement * ionfractions[ion]); + } else { + nnion = 0.; + } + } else { + nnion = MINPOP; + } + + const double groundpop = + nnion * stat_weight(element, ion, 0) / grid::modelgrid[modelgridindex].composition[element].partfunct[ion]; + + if (!std::isfinite(groundpop)) { + printout("[warning] calculate_ion_balance_nne: groundlevelpop infinite in connection with MINPOP\n"); + } + + grid::modelgrid[modelgridindex].composition[element].groundlevelpop[ion] = groundpop; + } +} + +static void set_groundlevelpops_neutral(const int modelgridindex) { + /// Special case of only neutral ions, set nne to some finite value that + /// packets are not lost in kpkts + printout("[warning] calculate_ion_balance_nne: only neutral ions in cell modelgridindex %d\n", modelgridindex); + for (int element = 0; element < get_nelements(); element++) { + const auto nnelement = grid::get_elem_numberdens(modelgridindex, element); + const int nions = get_nions(element); + /// Assign the species population to the neutral ion and set higher ions to MINPOP + for (int ion = 0; ion < nions; ion++) { + double nnion = NAN; + if (ion == 0) { + nnion = nnelement; + } else if (nnelement > 0.) { + nnion = MINPOP; + } else { + nnion = 0.; + } + const double groundpop = + (nnion * stat_weight(element, ion, 0) / grid::modelgrid[modelgridindex].composition[element].partfunct[ion]); + + grid::modelgrid[modelgridindex].composition[element].groundlevelpop[ion] = groundpop; + } + } +} + +static auto find_converged_nne(const int modelgridindex, double nne_hi, const bool force_lte) -> float { + /// Search solution for nne in [nne_lo,nne_hi] + + struct nne_solution_paras paras = {.modelgridindex = modelgridindex, .force_lte = force_lte}; + gsl_function f = {.function = &nne_solution_f, .params = ¶s}; + + double nne_lo = 0.; // MINPOP; + if (nne_solution_f(nne_lo, f.params) * nne_solution_f(nne_hi, f.params) > 0) { + const auto T_R = grid::get_TR(modelgridindex); + const auto T_e = grid::get_Te(modelgridindex); + const auto W = grid::get_W(modelgridindex); + printout("n, nne_lo, nne_hi, T_R, T_e, W, rho %d, %g, %g, %g, %g, %g, %g\n", modelgridindex, nne_lo, nne_hi, T_R, + T_e, W, grid::get_rho(modelgridindex)); + printout("nne@x_lo %g\n", nne_solution_f(nne_lo, f.params)); + printout("nne@x_hi %g\n", nne_solution_f(nne_hi, f.params)); + + for (int element = 0; element < get_nelements(); element++) { + printout("cell %d, element %d, uppermost_ion is %d\n", modelgridindex, element, + grid::get_elements_uppermost_ion(modelgridindex, element)); + + if constexpr (USE_LUT_PHOTOION) { + for (int ion = 0; ion <= grid::get_elements_uppermost_ion(modelgridindex, element); ion++) { + printout("element %d, ion %d, gammaionest %g\n", element, ion, + globals::gammaestimator[get_ionestimindex(modelgridindex, element, ion)]); + } + } + } + } + + double nne_solution = 0.; + + gsl_root_fsolver *solver = gsl_root_fsolver_alloc(gsl_root_fsolver_brent); + + gsl_root_fsolver_set(solver, &f, nne_lo, nne_hi); + constexpr int maxit = 50; + constexpr double fractional_accuracy = 1e-3; + int status = GSL_CONTINUE; + int iter = 0; + for (iter = 0; iter <= maxit; iter++) { + gsl_root_fsolver_iterate(solver); + nne_solution = gsl_root_fsolver_root(solver); + nne_lo = gsl_root_fsolver_x_lower(solver); + nne_hi = gsl_root_fsolver_x_upper(solver); + status = gsl_root_test_interval(nne_lo, nne_hi, 0, fractional_accuracy); + if (status != GSL_CONTINUE) { + break; + } + } + if (status == GSL_CONTINUE) { + printout("[warning] calculate_ion_balance_nne: nne did not converge within %d iterations\n", iter + 1); + } + + gsl_root_fsolver_free(solver); + + return std::max(MINPOP, nne_solution); +} + +auto calculate_ion_balance_nne(const int modelgridindex) -> void +/// Determines the electron number density for a given cell using one of +/// libgsl's root_solvers and calculates the depending level populations. +{ + const bool force_lte = globals::lte_iteration || grid::modelgrid[modelgridindex].thick == 1; + + const double nne_hi = grid::get_rho(modelgridindex) / MH; + + bool only_lowest_ionstage = true; // could be completely neutral, or just at each element's lowest ion stage + for (int element = 0; element < get_nelements(); element++) { + if (grid::get_elem_abundance(modelgridindex, element) > 0) { + const int uppermost_ion = find_uppermost_ion(modelgridindex, element, nne_hi, force_lte); + grid::set_elements_uppermost_ion(modelgridindex, element, uppermost_ion); + + only_lowest_ionstage = only_lowest_ionstage && (uppermost_ion <= 0); + } else { + grid::set_elements_uppermost_ion(modelgridindex, element, get_nions(element) - 1); + } + } + + if (only_lowest_ionstage) { + set_groundlevelpops_neutral(modelgridindex); + } else { + const auto nne_solution = find_converged_nne(modelgridindex, nne_hi, force_lte); + grid::set_nne(modelgridindex, nne_solution); + + for (int element = 0; element < get_nelements(); element++) { + // avoid overwriting the ground level populations set by the NLTE pop solver + const bool already_set_by_nlte_solver = !force_lte && elem_has_nlte_levels(element); + if (!already_set_by_nlte_solver) { + set_groundlevelpops(modelgridindex, element, nne_solution, force_lte); + } + } + } + + set_calculated_nne(modelgridindex); +} \ No newline at end of file diff --git a/ltepop.h b/ltepop.h index 1aeb12648..680e573ff 100644 --- a/ltepop.h +++ b/ltepop.h @@ -2,19 +2,21 @@ #define LTEPOP_H #include +#include #include "atomic.h" #include "sn3d.h" -double nne_solution_f(double x, void *paras); -void get_ionfractions(int element, int modelgridindex, double nne, double *ionfractions, int uppermost_ion); -double phi(int element, int ion, int modelgridindex); -double calculate_partfunct(int element, int ion, int modelgridindex); double get_groundlevelpop(int modelgridindex, int element, int ion); +double calculate_levelpop(int modelgridindex, int element, int ion, int level); double calculate_levelpop_lte(int modelgridindex, int element, int ion, int level); double get_levelpop(int modelgridindex, int element, int ion, int level); -double calculate_levelpop(int modelgridindex, int element, int ion, int level); double calculate_sahafact(int element, int ion, int level, int upperionlevel, double T, double E_threshold); -double ionstagepop(int modelgridindex, int element, int ion); +double get_nnion(int modelgridindex, int element, int ion); +void calculate_ion_balance_nne(int modelgridindex); +void calculate_cellpartfuncts(int modelgridindex, int element); +[[nodiscard]] auto calculate_ionfractions(const int element, const int modelgridindex, const double nne, + const bool force_lte) -> std::vector; +void set_groundlevelpops(const int modelgridindex, const int element, const float nne, const bool force_lte); #endif // LTEPOP_H diff --git a/macroatom.cc b/macroatom.cc index 9f12bf379..b0c52af7a 100644 --- a/macroatom.cc +++ b/macroatom.cc @@ -24,14 +24,16 @@ constexpr bool LOG_MACROATOM = false; static FILE *macroatom_file = nullptr; static void calculate_macroatom_transitionrates(const int modelgridindex, const int element, const int ion, - const int level, const double t_mid, struct chlevels *const chlevel) { + const int level, const double t_mid, struct chlevels &chlevel) { // printout("Calculating transition rates for element %d ion %d level %d\n", element, ion, level); - double *processrates = chlevel->processrates; + auto &processrates = chlevel.processrates; const auto T_e = grid::get_Te(modelgridindex); const auto nne = grid::get_nne(modelgridindex); const double epsilon_current = epsilon(element, ion, level); const double statweight = stat_weight(element, ion, level); + const auto &levelref = globals::elements[element].ions[ion].levels[level]; + /// Downward transitions within the current ionisation stage: /// radiative/collisional deexcitation and internal downward jumps processrates[MA_ACTION_RADDEEXC] = 0.; @@ -39,14 +41,15 @@ static void calculate_macroatom_transitionrates(const int modelgridindex, const processrates[MA_ACTION_INTERNALDOWNSAME] = 0.; const int ndowntrans = get_ndowntrans(element, ion, level); for (int i = 0; i < ndowntrans; i++) { - const int lower = globals::elements[element].ions[ion].levels[level].downtrans[i].targetlevelindex; - const auto A_ul = globals::elements[element].ions[ion].levels[level].downtrans[i].einstein_A; + const auto &downtransition = levelref.downtrans[i]; + const int lower = downtransition.targetlevelindex; + const auto A_ul = downtransition.einstein_A; const double epsilon_target = epsilon(element, ion, lower); const double epsilon_trans = epsilon_current - epsilon_target; const double R = rad_deexcitation_ratecoeff(modelgridindex, element, ion, level, lower, epsilon_trans, A_ul, statweight, t_mid); - const double C = col_deexcitation_ratecoeff(T_e, nne, epsilon_trans, element, ion, level, i); + const double C = col_deexcitation_ratecoeff(T_e, nne, epsilon_trans, element, ion, level, downtransition); const double individ_internal_down_same = (R + C) * epsilon_target; @@ -57,8 +60,8 @@ static void calculate_macroatom_transitionrates(const int modelgridindex, const processrates[MA_ACTION_COLDEEXC] += individ_col_deexc; processrates[MA_ACTION_INTERNALDOWNSAME] += individ_internal_down_same; - chlevel->sum_epstrans_rad_deexc[i] = processrates[MA_ACTION_RADDEEXC]; - chlevel->sum_internal_down_same[i] = processrates[MA_ACTION_INTERNALDOWNSAME]; + chlevel.sum_epstrans_rad_deexc[i] = processrates[MA_ACTION_RADDEEXC]; + chlevel.sum_internal_down_same[i] = processrates[MA_ACTION_INTERNALDOWNSAME]; // printout("checking downtrans %d to level %d: R %g, C %g, epsilon_trans %g\n",i,lower,R,C,epsilon_trans); } @@ -92,8 +95,9 @@ static void calculate_macroatom_transitionrates(const int modelgridindex, const processrates[MA_ACTION_INTERNALUPSAME] = 0.; const int nuptrans = get_nuptrans(element, ion, level); for (int i = 0; i < nuptrans; i++) { - const int upper = globals::elements[element].ions[ion].levels[level].uptrans[i].targetlevelindex; - const int lineindex = globals::elements[element].ions[ion].levels[level].uptrans[i].lineindex; + const auto &uptransition = globals::elements[element].ions[ion].levels[level].uptrans[i]; + const int upper = uptransition.targetlevelindex; + const int lineindex = uptransition.lineindex; const double epsilon_trans = epsilon(element, ion, upper) - epsilon_current; const double R = rad_excitation_ratecoeff(modelgridindex, element, ion, level, i, epsilon_trans, lineindex, t_mid); @@ -104,7 +108,7 @@ static void calculate_macroatom_transitionrates(const int modelgridindex, const const double individ_internal_up_same = (R + C + NT) * epsilon_current; processrates[MA_ACTION_INTERNALUPSAME] += individ_internal_up_same; - chlevel->sum_internal_up_same[i] = processrates[MA_ACTION_INTERNALUPSAME]; + chlevel.sum_internal_up_same[i] = processrates[MA_ACTION_INTERNALUPSAME]; } assert_always(std::isfinite(processrates[MA_ACTION_INTERNALUPSAME])); @@ -159,7 +163,6 @@ static void do_macroatom_raddeexcitation(struct packet *pkt_ptr, const int eleme const double rad_deexc, const int activatingline) { /// radiative deexcitation of MA: emitt rpkt /// randomly select which line transitions occurs - int linelistindex = -99; const int ndowntrans = get_ndowntrans(element, ion, level); double *sum_epstrans_rad_deexc = @@ -174,7 +177,7 @@ static void do_macroatom_raddeexcitation(struct packet *pkt_ptr, const int eleme const ptrdiff_t downtransindex = upperval - &sum_epstrans_rad_deexc[0]; assert_always(downtransindex < ndowntrans); - linelistindex = globals::elements[element].ions[ion].levels[level].downtrans[downtransindex].lineindex; + auto linelistindex = globals::elements[element].ions[ion].levels[level].downtrans[downtransindex].lineindex; if (linelistindex == activatingline) { stats::increment(stats::COUNTER_RESONANCESCATTERINGS); @@ -209,7 +212,7 @@ static void do_macroatom_raddeexcitation(struct packet *pkt_ptr, const int eleme pkt_ptr->last_event = 0; // emit the rpkt in a random direction - emitt_rpkt(pkt_ptr); + emit_rpkt(pkt_ptr); // the r-pkt can only interact with lines redder than the current one pkt_ptr->next_trans = linelistindex + 1; @@ -218,21 +221,18 @@ static void do_macroatom_raddeexcitation(struct packet *pkt_ptr, const int eleme pkt_ptr->em_time = pkt_ptr->prop_time; pkt_ptr->nscatterings = 0; - if constexpr (VPKT_ON) { - const int realtype = 3; - vpkt_call_estimators(pkt_ptr, pkt_ptr->prop_time, realtype); - } + vpkt_call_estimators(pkt_ptr, TYPE_MA); } static void do_macroatom_radrecomb(struct packet *pkt_ptr, const int modelgridindex, const int element, int *ion, int *level, const double rad_recomb) { const auto T_e = grid::get_Te(modelgridindex); - const float nne = grid::get_nne(modelgridindex); + const auto nne = grid::get_nne(modelgridindex); const double epsilon_current = epsilon(element, *ion, *level); const int upperion = *ion; const int upperionlevel = *level; /// Randomly select a continuum - double const zrand = rng_uniform(); + const double zrand = rng_uniform(); double rate = 0; const int nlevels = get_ionisinglevels(element, upperion - 1); int lower = 0; @@ -277,16 +277,11 @@ static void do_macroatom_radrecomb(struct packet *pkt_ptr, const int modelgridin pkt_ptr->last_event = 2; /// Finally emit the packet into a randomly chosen direction, update the continuum opacity and set some flags - emitt_rpkt(pkt_ptr); + emit_rpkt(pkt_ptr); if constexpr (TRACK_ION_STATS) { stats::increment_ion_stats(modelgridindex, element, upperion, stats::ION_RADRECOMB_MACROATOM, pkt_ptr->e_cmf / H / pkt_ptr->nu_cmf); - - const double escape_prob = get_rpkt_escape_prob(pkt_ptr, pkt_ptr->prop_time); - - stats::increment_ion_stats(modelgridindex, element, upperion, stats::ION_RADRECOMB_ESCAPED, - pkt_ptr->e_cmf / H / pkt_ptr->nu_cmf * escape_prob); } pkt_ptr->next_trans = 0; /// continuum transition, no restrictions for further line interactions @@ -295,16 +290,13 @@ static void do_macroatom_radrecomb(struct packet *pkt_ptr, const int modelgridin pkt_ptr->em_time = pkt_ptr->prop_time; pkt_ptr->nscatterings = 0; - if constexpr (VPKT_ON) { - const int realtype = 3; - vpkt_call_estimators(pkt_ptr, pkt_ptr->prop_time, realtype); - } + vpkt_call_estimators(pkt_ptr, TYPE_MA); } static void do_macroatom_ionisation(const int modelgridindex, const int element, int *ion, int *level, const double epsilon_current, const double internal_up_higher) { const auto T_e = grid::get_Te(modelgridindex); - const float nne = grid::get_nne(modelgridindex); + const auto nne = grid::get_nne(modelgridindex); int upper = -1; /// Randomly select the occuring transition @@ -339,17 +331,23 @@ static void do_macroatom_ionisation(const int modelgridindex, const int element, void do_macroatom(struct packet *pkt_ptr, const int timestep) /// Material for handling activated macro atoms. { + const int modelgridindex = grid::get_cell_modelgridindex(pkt_ptr->where); + const auto T_e = grid::get_Te(modelgridindex); + + // EXPERIMENT: disable macroatom and emit according to blackbody + // kpkt::do_kpkt_blackbody(pkt_ptr); + // stats::increment(stats::COUNTER_RESONANCESCATTERINGS); + // pkt_ptr->interactions++; + // return; + const int tid = get_thread_num(); - const double t_mid = globals::time_step[timestep].mid; + const double t_mid = globals::timesteps[timestep].mid; // printout("[debug] do MA\n"); - const int cellindex = pkt_ptr->where; - const int modelgridindex = grid::get_cell_modelgridindex(cellindex); - const auto T_e = grid::get_Te(modelgridindex); - const float nne = grid::get_nne(modelgridindex); + const auto nne = grid::get_nne(modelgridindex); - assert_always(grid::modelgrid[modelgridindex].thick != 1); // macroatom should not be used in thick cells + assert_testmodeonly(grid::modelgrid[modelgridindex].thick != 1); // macroatom should not be used in thick cells /// calculate occupation number for active MA level //////////////////////////////////// /// general QUESTION: is it better to calculate the n_1 (later the n_ionstage and @@ -390,17 +388,17 @@ void do_macroatom(struct packet *pkt_ptr, const int timestep) // printout("[debug] %s Z=%d ionstage %d level %d, jumps %d\n", __func__, get_atomicnumber(element), // get_ionstage(element,ion), level, jumps); - assert_always(ion >= 0); - assert_always(ion < get_nions(element)); + assert_testmodeonly(ion >= 0); + assert_testmodeonly(ion < get_nions(element)); const double epsilon_current = epsilon(element, ion, level); // const int ndowntrans = get_ndowntrans(element, ion, level); const int nuptrans = get_nuptrans(element, ion, level); - assert_always(globals::cellhistory[tid].cellnumber == modelgridindex); + assert_testmodeonly(globals::cellhistory[tid].cellnumber == modelgridindex); - struct chlevels *chlevel = &globals::cellhistory[tid].chelements[element].chions[ion].chlevels[level]; - const double *processrates = chlevel->processrates; + auto &chlevel = globals::cellhistory[tid].chelements[element].chions[ion].chlevels[level]; + auto &processrates = chlevel.processrates; /// If there are no precalculated rates available then calculate them if (processrates[MA_ACTION_COLDEEXC] < 0) { calculate_macroatom_transitionrates(modelgridindex, element, ion, level, t_mid, chlevel); @@ -766,14 +764,14 @@ auto rad_excitation_ratecoeff(const int modelgridindex, const int element, const const double tau_sobolev = (B_lu * n_l - B_ul * n_u) * HCLIGHTOVERFOURPI * t_current; if (tau_sobolev > 1e-100) { - double const beta = 1.0 / tau_sobolev * (-std::expm1(-tau_sobolev)); + const double beta = 1.0 / tau_sobolev * (-std::expm1(-tau_sobolev)); const double R_over_J_nu = n_l > 0. ? (B_lu - B_ul * n_u / n_l) * beta : B_lu * beta; R = R_over_J_nu * radfield::radfield(nu_trans, modelgridindex); if constexpr (DETAILED_LINE_ESTIMATORS_ON) { - if (!globals::initial_iteration) { + if (!globals::lte_iteration) { // check for a detailed line flux estimator to replace the binned/blackbody radiation field estimate const int jblueindex = radfield::get_Jblueindex(lineindex); if (jblueindex >= 0) { @@ -890,7 +888,7 @@ auto col_recombination_ratecoeff(const int modelgridindex, const int element, co const double sf = calculate_sahafact(element, upperion - 1, lower, upper, T_e, epsilon_trans); - double const C = nne * nne * sf * 1.55e13 * pow(T_e, -0.5) * g * sigma_bf * exp(-fac1) / fac1; + const double C = nne * nne * sf * 1.55e13 * pow(T_e, -0.5) * g * sigma_bf * exp(-fac1) / fac1; return C; } @@ -933,17 +931,16 @@ auto col_ionization_ratecoeff(const float T_e, const float nne, const int elemen } auto col_deexcitation_ratecoeff(const float T_e, const float nne, const double epsilon_trans, int element, int ion, - int upper, int downtransindex) -> double + int upper, const struct level_transition &downtransition) -> double // multiply by upper level population to get a rate per second { - const int lower = globals::elements[element].ions[ion].levels[upper].downtrans[downtransindex].targetlevelindex; + const int lower = downtransition.targetlevelindex; const double upperstatweight = stat_weight(element, ion, upper); const double lowerstatweight = stat_weight(element, ion, lower); - const double coll_str_thisline = - globals::elements[element].ions[ion].levels[upper].downtrans[downtransindex].coll_str; + const double coll_str_thisline = downtransition.coll_str; double C = 0.; if (coll_str_thisline < 0) { - const bool forbidden = globals::elements[element].ions[ion].levels[upper].downtrans[downtransindex].forbidden; + const bool forbidden = downtransition.forbidden; if (!forbidden) // alternative: (coll_strength > -1.5) i.e. to catch -1 { /// permitted E1 electric dipole transitions @@ -952,8 +949,7 @@ auto col_deexcitation_ratecoeff(const float T_e, const float nne, const double e // f = osc_strength(element,ion,upper,lower); // C = n_u * 2.16 * pow(fac1,-1.68) * pow(T_e,-1.5) * // stat_weight(element,ion,lower)/stat_weight(element,ion,upper) * nne * f; - const double trans_osc_strength = - globals::elements[element].ions[ion].levels[upper].downtrans[downtransindex].osc_strength; + const double trans_osc_strength = downtransition.osc_strength; const double eoverkt = epsilon_trans / (KB * T_e); /// Van-Regemorter formula, Mihalas (1978), eq.5-75, p.133 diff --git a/macroatom.h b/macroatom.h index c03c39f83..1bc6ccf6c 100644 --- a/macroatom.h +++ b/macroatom.h @@ -49,7 +49,7 @@ double col_ionization_ratecoeff(float T_e, float nne, int element, int ion, int double epsilon_trans); double col_deexcitation_ratecoeff(float T_e, float nne, double epsilon_trans, int element, int ion, int upper, - int downtransindex); + const struct level_transition &downtransition); double col_excitation_ratecoeff(float T_e, float nne, int element, int ion, int lower, int uptransindex, double epsilon_trans, double lowerstatweight); diff --git a/nltepop.cc b/nltepop.cc index ac7e816f7..94c3e516c 100644 --- a/nltepop.cc +++ b/nltepop.cc @@ -403,30 +403,35 @@ static void nltepop_reset_element(const int modelgridindex, const int element) { } } -static auto get_element_nlte_dimension_and_slpartfunc(const int modelgridindex, const int element, const int nions, - std::unique_ptr &superlevel_partfunc) -> int { - int nlte_dimension = 0; +static auto get_element_superlevelpartfuncs(const int modelgridindex, const int element) -> std::vector { + const int nions = get_nions(element); + std::vector superlevel_partfuncs(nions, 0.); for (int ion = 0; ion < nions; ion++) { - superlevel_partfunc[ion] = 0.; - const int nlevels_nlte = get_nlevels_nlte(element, ion); - - // this is the total number of nlte_levels (i.e. the size of the - // storage). Our rate matrix will need to be of this dimension +2: the - // ground state, the "super level". - // If there's no super level needed then we only need +1 if (ion_has_superlevel(element, ion)) { - nlte_dimension += nlevels_nlte + 2; + const int nlevels_nlte = get_nlevels_nlte(element, ion); const int nlevels = get_nlevels(element, ion); for (int level = nlevels_nlte + 1; level < nlevels; level++) { - superlevel_partfunc[ion] += superlevel_boltzmann(modelgridindex, element, ion, level); + superlevel_partfuncs[ion] += superlevel_boltzmann(modelgridindex, element, ion, level); } - // printout(" NLTE: including ion_stage %d, which contributes %d to the vector dimension (including superlevel - // with partfunc %g)\n", - // get_ionstage(element, ion), nlevels_nlte + 2, superlevel_partfunc[ion]); } else { - nlte_dimension += nlevels_nlte + 1; - // printout(" NLTE: including ion_stage %d, which contributes %d to the vector dimension (no super level)\n", - // get_ionstage(element, ion), nlevels_nlte + 1); + superlevel_partfuncs[ion] = 0.; + } + } + + return superlevel_partfuncs; +} + +static auto get_element_nlte_dimension(const int element) -> int { + int nlte_dimension = 0; + const int nions = get_nions(element); + for (int ion = 0; ion < nions; ion++) { + const int nlevels_nlte = get_nlevels_nlte(element, ion); + + nlte_dimension += nlevels_nlte + 1; // ground state is not counted in nlevels_nlte + + // add super level if it exists + if (ion_has_superlevel(element, ion)) { + nlte_dimension++; } } @@ -434,7 +439,7 @@ static auto get_element_nlte_dimension_and_slpartfunc(const int modelgridindex, } static void nltepop_matrix_add_boundbound(const int modelgridindex, const int element, const int ion, - const double t_mid, std::unique_ptr &s_renorm, + const double t_mid, const std::vector &s_renorm, gsl_matrix *rate_matrix_rad_bb, gsl_matrix *rate_matrix_coll_bb, gsl_matrix *rate_matrix_ntcoll_bb) { const auto T_e = grid::get_Te(modelgridindex); @@ -448,15 +453,17 @@ static void nltepop_matrix_add_boundbound(const int modelgridindex, const int el // de-excitation const int ndowntrans = get_ndowntrans(element, ion, level); for (int i = 0; i < ndowntrans; i++) { - const double A_ul = globals::elements[element].ions[ion].levels[level].downtrans[i].einstein_A; - const int lower = globals::elements[element].ions[ion].levels[level].downtrans[i].targetlevelindex; + const auto &downtransition = globals::elements[element].ions[ion].levels[level].downtrans[i]; + const double A_ul = downtransition.einstein_A; + const int lower = downtransition.targetlevelindex; const double epsilon_trans = epsilon_level - epsilon(element, ion, lower); const double R = rad_deexcitation_ratecoeff(modelgridindex, element, ion, level, lower, epsilon_trans, A_ul, statweight, t_mid) * s_renorm[level]; - const double C = col_deexcitation_ratecoeff(T_e, nne, epsilon_trans, element, ion, level, i) * s_renorm[level]; + const double C = + col_deexcitation_ratecoeff(T_e, nne, epsilon_trans, element, ion, level, downtransition) * s_renorm[level]; const int upper_index = level_index; const int lower_index = get_nlte_vector_index(element, ion, lower); @@ -523,7 +530,7 @@ static void nltepop_matrix_add_boundbound(const int modelgridindex, const int el } static void nltepop_matrix_add_ionisation(const int modelgridindex, const int element, const int ion, - std::unique_ptr &s_renorm, gsl_matrix *rate_matrix_rad_bf, + const std::vector &s_renorm, gsl_matrix *rate_matrix_rad_bf, gsl_matrix *rate_matrix_coll_bf) { assert_always(ion + 1 < get_nions(element)); // can't ionise the top ion const auto T_e = grid::get_Te(modelgridindex); @@ -582,7 +589,7 @@ static void nltepop_matrix_add_ionisation(const int modelgridindex, const int el } static void nltepop_matrix_add_nt_ionisation(const int modelgridindex, const int element, const int ion, - std::unique_ptr &s_renorm, gsl_matrix *rate_matrix_ntcoll_bf) { + const std::vector &s_renorm, gsl_matrix *rate_matrix_ntcoll_bf) { // collisional ionization by non-thermal electrons assert_always(ion + 1 < get_nions(element)); // can't ionise the top ion @@ -619,6 +626,7 @@ static void nltepop_matrix_normalise(const int modelgridindex, const int element // TODO: consider replacing normalisation by LTE populations with // GSL's gsl_linalg_balance_matrix(gsl_matrix * A, gsl_vector * D) function instead + set_groundlevelpops(modelgridindex, element, grid::get_nne(modelgridindex), true); for (size_t column = 0; column < nlte_dimension; column++) { int ion = -1; int level = -1; @@ -649,29 +657,10 @@ static void nltepop_matrix_normalise(const int modelgridindex, const int element } static void set_element_pops_lte(const int modelgridindex, const int element) { - nltepop_reset_element(modelgridindex, element); - - // const int nions = get_nions(element); - // for (int ion = 0; ion < nions; ion++) - // grid::modelgrid[modelgridindex].composition[element].partfunct[ion] = calculate_partfunct(element, ion, - // modelgridindex); - // - // const float nne = grid::get_nne(modelgridindex); - // const double elem_meanweight = grid::get_element_meanweight(modelgridindex, element); - // const double nnelement = grid::get_elem_abundance(modelgridindex, element) / elem_meanweight * - // grid::get_rho(modelgridindex); for (int ion = 0; ion < nions; ion++) - // { - // double nnion; - // if (ion == 0) - // nnion = nnelement * ionfract(element, ion, modelgridindex, nne); - // else - // nnion = MINPOP; - // - // grid::modelgrid[modelgridindex].composition[element].groundlevelpop[ion] = ( - // nnion * stat_weight(element,ion,0) / grid::modelgrid[modelgridindex].composition[element].partfunct[ion]); - // - // assert_always(std::isfinite(grid::modelgrid[modelgridindex].composition[element].groundlevelpop[ion])); - // } + nltepop_reset_element(modelgridindex, element); // set NLTE pops as invalid so that LTE pops will be used instead + + calculate_cellpartfuncts(modelgridindex, element); + set_groundlevelpops(modelgridindex, element, grid::get_nne(modelgridindex), true); } static auto lumatrix_is_singular(const gsl_matrix *LU, const int element) -> bool { @@ -835,7 +824,7 @@ void solve_nlte_pops_element(const int element, const int modelgridindex, const const time_t sys_time_start_nltesolver = time(nullptr); - const double t_mid = globals::time_step[timestep].mid; + const double t_mid = globals::timesteps[timestep].mid; const int nions = get_nions(element); const double nnelement = grid::get_elem_numberdens(modelgridindex, element); @@ -844,15 +833,8 @@ void solve_nlte_pops_element(const int element, const int modelgridindex, const "population %.2e)\n", modelgridindex, timestep, nlte_iter, atomic_number, grid::get_elem_abundance(modelgridindex, element), nnelement); - // LTE test, make sure binned radfield is off - // grid::set_TR(modelgridindex,3000); - // grid::set_W(modelgridindex,1.0); - // printout("T_E %g T_R was %g, setting to 3000 \n",grid::get_Te(modelgridindex),get_TR(modelgridindex)); - - auto superlevel_partfunc = - std::make_unique(nions); // space is allocated for every ion, even if it does not have a superlevel - const int nlte_dimension = - get_element_nlte_dimension_and_slpartfunc(modelgridindex, element, nions, superlevel_partfunc); + auto superlevel_partfunc = std::vector(nions) = get_element_superlevelpartfuncs(modelgridindex, element); + const int nlte_dimension = get_element_nlte_dimension(element); // printout("NLTE: the vector dimension is %d", nlte_dimension); @@ -882,10 +864,7 @@ void solve_nlte_pops_element(const int element, const int modelgridindex, const gsl_vector *const balance_vector = gsl_vector_calloc(nlte_dimension); - if (balance_vector == nullptr) { - printout("Cannot allocate NLTE rate matrix/balance vector memory.\n"); - abort(); - } + assert_always(balance_vector != nullptr); // printout(" Adding rates for ion stages:"); for (int ion = 0; ion < nions; ion++) { @@ -895,7 +874,7 @@ void solve_nlte_pops_element(const int element, const int modelgridindex, const const int nlevels = get_nlevels(element, ion); const int nlevels_nlte = get_nlevels_nlte(element, ion); - auto s_renorm = std::make_unique(nlevels); + auto s_renorm = std::vector(nlevels); for (int level = 0; level <= nlevels_nlte; level++) { s_renorm[level] = 1.0; } @@ -934,6 +913,25 @@ void solve_nlte_pops_element(const int element, const int modelgridindex, const // set first balance vector entry to the element population (all other entries will be zero) gsl_vector_set(balance_vector, 0, nnelement); + if (FORCE_SAHA_ION_BALANCE(atomic_number)) { + const auto ionfractions = calculate_ionfractions(element, modelgridindex, grid::get_nne(modelgridindex), true); + const int uppermost_ion = static_cast(ionfractions.size() - 1); + for (int ion = 1; ion <= uppermost_ion; ion++) { + // replace matrix row for ion's ground state with sum of this ion's level populations is equal to the ion + // population + const double nnion = nnelement * ionfractions[ion]; + const int index_ion_ground = get_nlte_vector_index(element, ion, 0); + const int index_ion_toplevel = get_nlte_vector_index(element, ion, get_nlevels(element, ion)); + gsl_vector_view ion_ground_row_view = gsl_matrix_row(rate_matrix, index_ion_ground); + gsl_vector_set_all(&ion_ground_row_view.vector, 0.); + for (int index = index_ion_ground; index <= index_ion_toplevel; index++) { + gsl_vector_set(&ion_ground_row_view.vector, index, 1.); + } + + gsl_vector_set(balance_vector, get_nlte_vector_index(element, ion, index_ion_ground), nnion); + } + } + // calculate the normalisation factors and apply them to the matrix // columns and balance vector elements gsl_vector *pop_norm_factor_vec = gsl_vector_calloc(nlte_dimension); @@ -977,7 +975,6 @@ void solve_nlte_pops_element(const int element, const int modelgridindex, const assert_always(gsl_vector_get(popvec, index) >= 0.); } - // double ion_populations[nions]; for (int ion = 0; ion < nions; ion++) { const int nlevels_nlte = get_nlevels_nlte(element, ion); const int index_gs = get_nlte_vector_index(element, ion, 0); @@ -1005,76 +1002,22 @@ void solve_nlte_pops_element(const int element, const int modelgridindex, const const int index_sl = get_nlte_vector_index(element, ion, nlevels_nlte + 1); grid::modelgrid[modelgridindex].nlte_pops[nlte_start + nlevels_nlte] = (gsl_vector_get(popvec, index_sl) / grid::modelgrid[modelgridindex].rho / superlevel_partfunc[ion]); - - // printout("solve_nlte_pops_element: The Z=%d ionstage %d superlevel population is %g with rho %g and - // superlevel_partfunc %g Te %g scaled pop stored as %g\n", get_atomicnumber(element), get_ionstage(element, - // ion), gsl_vector_get(popvec, index_sl), grid::modelgrid[modelgridindex].rho, superlevel_partfunc[ion], - // grid::get_Te(modelgridindex), grid::modelgrid[modelgridindex].nlte_pops[nlte_start + nlevels_nlte]); the - // stored population is already divided by the partfunc, so just multiply it by the superlevel_boltzmann to get - // the population of a level in the SL - - // solution_ion_pop += gsl_vector_get(popvec, index_sl); } - // printout(" I had a ground level pop of %g, a part fn of %g and therefore an ion pop of %g\n", - // grid::modelgrid[modelgridindex].composition[element].groundlevelpop[ion], - // grid::modelgrid[modelgridindex].composition[element].partfunct[ion], - // (grid::modelgrid[modelgridindex].composition[element].partfunct[ion] * - // grid::modelgrid[modelgridindex].composition[element].groundlevelpop[ion] - // / stat_weight(element, ion, 0))); - - // ionstagepop here must be called before setting the new ground level population - // printout(" For ion_stage %d the total population is %g, but was previously %g\n", - // ion_stage,solution_ion_pop,ionstagepop(modelgridindex, element, ion)); // store the ground level population grid::modelgrid[modelgridindex].composition[element].groundlevelpop[ion] = gsl_vector_get(popvec, index_gs); // solution_ion_pop += gsl_vector_get(popvec, index_gs); - precalculate_partfuncts(modelgridindex); - - // ion_populations[ion] = solution_ion_pop; - // if (ion > 0) - // { - // const double gspopratio = grid::modelgrid[modelgridindex].composition[element].groundlevelpop[ion-1] / - // grid::modelgrid[modelgridindex].composition[element].groundlevelpop[ion]; - // - // const double ionpot = epsilon(element,ion,0) - epsilon(element,ion-1,0); - // const auto T_e = grid::get_Te(modelgridindex); - // const double partfunct_ratio = grid::modelgrid[modelgridindex].composition[element].partfunct[ion-1] / - // grid::modelgrid[modelgridindex].composition[element].partfunct[ion]; const double gs_g_ratio = - // stat_weight(element,ion-1,0) / stat_weight(element,ion,0); const double sbphi_gs = gs_g_ratio * SAHACONST * - // pow(T_e,-1.5) * exp(ionpot/KB/T_e) * grid::get_nne(modelgridindex); const double solution_ion_pop_ratio = - // ion_populations[ion-1] / ion_populations[ion]; const double sbphi = partfunct_ratio * SAHACONST * - // pow(T_e,-1.5) * exp(ionpot/KB/T_e) * grid::get_nne(modelgridindex); - // - // printout(" The ratio of groundlevel pops (ion %d)/(ion %d) is %g, Saha-Boltzmann value is %g ratio %g\n", - // get_ionstage(element,ion-1),ion_stage,gspopratio,sbphi_gs,gspopratio/sbphi_gs); - // printout(" The ratio of total pops (ion %d)/(ion %d) is %g, Saha-Boltzmann value is %g ratio %g\n", - // get_ionstage(element,ion-1),ion_stage,solution_ion_pop_ratio,sbphi,solution_ion_pop_ratio/sbphi); - // const float nne = grid::get_nne(modelgridindex); - // // calculate_partfunct(element, ion, modelgridindex) * - // grid::modelgrid[modelgridindex].composition[element].groundlevelpop[ion] / stat_weight(element,ion,0)) - // printout(" The corresponding phi-factor is: %g\n", (solution_ion_pop_ratio / nne)); - // printout(" The ionization solver gives phi(ion_stage=%d / %d) = %g\n", - // get_ionstage(element, ion-1), get_ionstage(element, ion), phi(element, ion-1, modelgridindex)); - // } - - // double nne = grid::get_nne(modelgridindex); - // printout(" From ion fract, the ion pop should be %g\n", ionfract(element, ion, modelgridindex, - // nne)*nnelement); printout(" I think that the element population is: %g (from abundance %g and rho %g)\n", - // grid::get_elem_abundance(modelgridindex,element)/elem_meanweight*grid::get_rho(modelgridindex), - // grid::get_elem_abundance(modelgridindex,element), grid::get_rho(modelgridindex)); printout(" I currently think - // that the top ion is: %d\n", elements_uppermost_ion[tid][element]); + calculate_cellpartfuncts(modelgridindex, element); } - const double elem_pop_abundance = nnelement; const double elem_pop_matrix = gsl_blas_dasum(popvec); - const double elem_pop_error_percent = fabs((elem_pop_abundance / elem_pop_matrix) - 1) * 100; + const double elem_pop_error_percent = fabs((nnelement / elem_pop_matrix) - 1) * 100; if (elem_pop_error_percent > 1.0) { printout( " WARNING: The Z=%d element population is: %g (from abundance) and %g (from matrix solution sum of level " "pops), error: %.1f%%. Forcing element pops to LTE.\n", - atomic_number, elem_pop_abundance, elem_pop_matrix, elem_pop_error_percent); + atomic_number, nnelement, elem_pop_matrix, elem_pop_error_percent); set_element_pops_lte(modelgridindex, element); } @@ -1086,7 +1029,7 @@ void solve_nlte_pops_element(const int element, const int modelgridindex, const rate_matrix_ntcoll_bf); } - bool const print_detailed_level_stats = false; + const bool print_detailed_level_stats = false; // if ((atomic_number == 26) && ((timestep % 5) == 0) && (nlte_iter == 0)) // { @@ -1132,431 +1075,6 @@ void solve_nlte_pops_element(const int element, const int modelgridindex, const } } -// this does single ion solving and will be deprecated at some point -auto solve_nlte_pops_ion(int element, int ion, int modelgridindex, int timestep) -> double -// solves for nlte correction factors to level populations for levels -{ - if (!(get_nlevels(element, ion) > 1)) { - return 0.; - } - - double *rate_matrix = nullptr; - double *balance_vector = nullptr; - - double test_ratio = 0.; - - const auto T_e = grid::get_Te(modelgridindex); - const float nne = grid::get_nne(modelgridindex); - - printout( - "Solving for NLTE populations in cell %d. Doing Z=%d ionstage %d (element %d, ion %d). I think it's timestep " - "%d\n", - modelgridindex, get_atomicnumber(element), get_ionstage(element, ion), element, ion, timestep); - // printout("Current Te %g and ne %g\n",T_e, nne); - - const int nlevels_nlte = get_nlevels_nlte(element, ion); - const double t_mid = globals::time_step[timestep].mid; - - int nlte_size = 0; - bool super_level = false; - if (!ion_has_superlevel(element, ion)) { - nlte_size = nlevels_nlte + 2; - super_level = false; - } else { - nlte_size = nlevels_nlte + 3; - super_level = true; - } - // that's the total number of nlte_levels (i.e. the size of the - // storage). Our rate matrix will need to be of this dimension +3: the - // ground state, the "super level" and the ground state of the ion - // above. If there's no super level needed then we only need +2 - int const nlte_start = globals::elements[element].ions[ion].first_nlte; - - // if (get_groundlevelpop(modelgridindex,element,ion) > (1.2*MINPOP)) - if (grid::get_elem_abundance(modelgridindex, element) > 0.0) { - rate_matrix = static_cast(calloc(nlte_size * nlte_size, sizeof(double))); - assert_always(rate_matrix != nullptr); - - balance_vector = static_cast(calloc(nlte_size, sizeof(double))); - assert_always(balance_vector != nullptr); - - // printf("rate %p balance %p NULL %p\n", rate_matrix, balance_vector,nullptr); - // printout("I think there are %d levels to deal with and managed to allocate memory.\n", nlte_size); - - double superlevel_partition = 0.0; - for (int level = 1; level < get_nlevels(element, ion); level++) { - if (!is_nlte(element, ion, level)) { - printout("element %d ion %d level %d is in the superlevel\n", element, ion, level); - superlevel_partition += superlevel_boltzmann(modelgridindex, element, ion, level); - assert_always(std::isfinite(superlevel_partition)); - } - } - - double upperion_partition = 0.0; - if (ion < get_nions(element)) { - for (int level = 0; level < get_nlevels(element, ion + 1); level++) { - upperion_partition += get_levelpop(modelgridindex, element, ion + 1, level); - } - } - assert_always(std::isfinite(upperion_partition)); - - if (superlevel_partition > 0.0) { - printout("I found a superlevel and have computed a partition function for its substates of %g.\n", - superlevel_partition); - } else { - printout("I don't know about any super level for this case.\n"); - } - - const int nlevels = get_nlevels(element, ion); - const int nlevels_nlte = get_nlevels_nlte(element, ion); - auto s_renorm = std::make_unique(nlevels); - - for (int level = 0; level < nlevels; level++) { - if (level == 0 || (is_nlte(element, ion, level))) { - s_renorm[level] = 1.0; - } else { - s_renorm[level] = superlevel_boltzmann(modelgridindex, element, ion, level) / superlevel_partition; - } - } - - for (int level = 0; level < get_nlevels(element, ion); level++) { - const double epsilon_current = epsilon(element, ion, level); - const double statweight = stat_weight(element, ion, level); - - // deexcitation - const int ndowntrans = get_ndowntrans(element, ion, level); - for (int i = 0; i < ndowntrans; i++) { - const double A_ul = globals::elements[element].ions[ion].levels[level].downtrans[i].einstein_A; - const int lower = globals::elements[element].ions[ion].levels[level].downtrans[i].targetlevelindex; - const double epsilon_trans = epsilon_current - epsilon(element, ion, lower); - - const double R = rad_deexcitation_ratecoeff(modelgridindex, element, ion, level, lower, epsilon_trans, A_ul, - statweight, t_mid); - assert_always(std::isfinite(R)); - const double C = col_deexcitation_ratecoeff(T_e, nne, epsilon_trans, element, ion, level, i); - assert_always(std::isfinite(C)); - - int level_use = 0; - if ((level == 0) || is_nlte(element, ion, level)) { - level_use = level; - } else { - level_use = nlevels_nlte + 1; - } - - int lower_use = 0; - if ((lower == 0) || (is_nlte(element, ion, lower))) { - lower_use = lower; - } else { - lower_use = nlevels_nlte + 1; - } - - // printout("First using %d of %d\n", level_use*(nlte_size) + level_use, nlte_size*nlte_size); - // printout("Second using %d of %d\n", lower_use*(nlte_size) + level_use, nlte_size*nlte_size); - rate_matrix[level_use * nlte_size + level_use] -= (R + C) * s_renorm[level]; - rate_matrix[lower_use * nlte_size + level_use] += (R + C) * s_renorm[level]; - } - - // excitation - const int nuptrans = get_nuptrans(element, ion, level); - for (int i = 0; i < nuptrans; i++) { - // printout(" level %d excitation i %d\n", level, i); - const int lineindex = globals::elements[element].ions[ion].levels[level].uptrans[i].lineindex; - const struct linelist_entry *line = &globals::linelist[lineindex]; - const int upper = line->upperlevelindex; - const double epsilon_trans = epsilon(element, ion, upper) - epsilon_current; - - const double R = - rad_excitation_ratecoeff(modelgridindex, element, ion, level, i, epsilon_trans, lineindex, t_mid); - assert_always(std::isfinite(R)); - const double C = col_excitation_ratecoeff(T_e, nne, element, ion, level, i, epsilon_trans, statweight); - assert_always(std::isfinite(C)); - - int level_use = 0; - double s_renorm = 1.; - if ((level == 0) || (is_nlte(element, ion, level))) { - level_use = level; - s_renorm = 1.; - } else { - level_use = nlevels_nlte + 1; - s_renorm = superlevel_boltzmann(modelgridindex, element, ion, level) / superlevel_partition; - } - assert_always(std::isfinite(s_renorm)); - - int upper_use = 0; - if ((upper == 0) || (is_nlte(element, ion, upper))) { - upper_use = upper; - } else { - upper_use = nlevels_nlte + 1; - } - // printout("Third using %d of %d\n", level_use*(nlte_size) + level_use, nlte_size*nlte_size); - // printout("Fourth using %d of %d\n", upper_use*(nlte_size) + level_use, nlte_size*nlte_size); - rate_matrix[level_use * nlte_size + level_use] -= (R + C) * s_renorm; - rate_matrix[upper_use * nlte_size + level_use] += (R + C) * s_renorm; - } - - // printout("nt_ion\n"); - if (NT_ON && ion < get_nions(element) - 1) { - const double Y = nonthermal::nt_ionization_ratecoeff(modelgridindex, element, ion); - - int level_use = 0; - double s_renorm = 1.0; - if ((level == 0) || (is_nlte(element, ion, level))) { - level_use = level; - s_renorm = 1.0; - } else { - level_use = nlevels_nlte + 1; // the super level - s_renorm = superlevel_boltzmann(modelgridindex, element, ion, level) / superlevel_partition; - } - assert_always(std::isfinite(s_renorm)); - - const int upper_use = nlte_size - 1; // the continuum - rate_matrix[level_use * nlte_size + level_use] -= Y * s_renorm; - rate_matrix[upper_use * nlte_size + level_use] += Y * s_renorm; - } - - // now put in the photoionization/recombination processes - const int ionisinglevels = get_ionisinglevels(element, ion); - if ((ion < get_nions(element) - 1) && (level < ionisinglevels)) { - double s_renorm = 1.; - - int level_use = 0; - if ((level == 0) || (is_nlte(element, ion, level))) { - level_use = level; - } else { - level_use = nlevels_nlte + 1; // the super level - s_renorm = superlevel_boltzmann(modelgridindex, element, ion, level) / superlevel_partition; - } - assert_always(std::isfinite(s_renorm)); - - // printout("ionization\n"); - // ionization - const int upper_use = nlte_size - 1; // ion above - for (int phixstargetindex = 0; phixstargetindex < get_nphixstargets(element, ion, level); phixstargetindex++) { - const int upper = get_phixsupperlevel(element, ion, level, phixstargetindex); - const double epsilon_trans = epsilon(element, ion + 1, upper) - epsilon_current; - const double R = get_corrphotoioncoeff(element, ion, level, phixstargetindex, modelgridindex); - assert_always(std::isfinite(R)); - const double C = col_ionization_ratecoeff(T_e, nne, element, ion, level, phixstargetindex, epsilon_trans); - assert_always(std::isfinite(C)); - - rate_matrix[level_use * (nlte_size) + level_use] -= (R + C) * s_renorm; - rate_matrix[upper_use * (nlte_size) + level_use] += (R + C) * s_renorm; - } - - // printout("recombination\n"); - // recombination - for (int phixstargetindex = 0; phixstargetindex < get_nphixstargets(element, ion, level); phixstargetindex++) { - const int upper = get_phixsupperlevel(element, ion, level, phixstargetindex); - const double epsilon_trans = epsilon(element, ion + 1, upper) - epsilon_current; - const double R = rad_recombination_ratecoeff(T_e, nne, element, ion + 1, upper, level, modelgridindex); - assert_always(std::isfinite(R)); - // printout("rad recombination of element %d, ion %d, level %d, to lower level %d has rate %g (ne %g and Te - // %g)\n",element,ion,pkt_ptr->mastate.level,level,R/nne,nne,T_e); printout("%d %d %d %d %g %g %g - // \n",element,ion,pkt_ptr->mastate.level,level,R/nne,nne,T_e); - const double C = col_recombination_ratecoeff(modelgridindex, element, ion + 1, upper, level, epsilon_trans); - assert_always(std::isfinite(C)); - // C=C*1.e-10; - - double const upper_renorm = get_levelpop(modelgridindex, element, ion + 1, upper) / upperion_partition; - assert_always(std::isfinite(upper_renorm)); - // TODO: would the line below be correct, or is it equal to the above line? - // double upper_renorm = superlevel_boltzmann(modelgridindex,element,ion+1,upper) / upperion_partition; - rate_matrix[upper_use * (nlte_size) + upper_use] -= (R + C) * upper_renorm; - rate_matrix[level_use * (nlte_size) + upper_use] += (R + C) * upper_renorm; - } - - // balance_vector[level_use] += -1. * get_groundlevelpop(modelgridindex,element,ion+1) * (R + C); - } - } - - // replace the first line of the matrix with the normalisation constraint - printout("replace the first line of the matrix with the normalisation constraint\n"); - rate_matrix[0] = 1.0; - balance_vector[0] = ionstagepop(modelgridindex, element, ion); - for (int level = 1; level < nlte_size; level++) { - rate_matrix[level] = 1.0; - balance_vector[level] = 0.0; - } - rate_matrix[nlte_size - 1] = 0.0; - - for (int level = 0; level < nlte_size; level++) { - for (int level_use = 0; level_use < nlte_size; level_use++) { - // printout("%g ", rate_matrix[level*nlte_size + level_use]); - if (!std::isfinite(rate_matrix[level * nlte_size + level_use])) { - printout("[fatal]: NLTE matrix with non-finite element: %d %d %g\n", level, level_use, - rate_matrix[level * nlte_size + level_use]); - printout("[fatal]: found when handling element %d and ion %d\n", element, ion); - printout("[fatal]: the relevant ground state populations are %g and %g\n", - get_groundlevelpop(modelgridindex, element, ion), - get_groundlevelpop(modelgridindex, element, ion + 1)); - abort(); - } - } - // printout("\n"); - } - // printout("\n"); - - for (int level = 0; level < nlte_size; level++) { - // printout("%g ",balance_vector[level] ); - if (!std::isfinite(balance_vector[level])) { - printout("[fatal]: NLTE balance with non-finite element: %d %g\n", level, balance_vector[level]); - printout("[fatal]: found when handling element %d and ion %d\n", element, ion); - printout("[fatal]: the relevant ground state populations are %g and %g\n", - get_groundlevelpop(modelgridindex, element, ion), - get_groundlevelpop(modelgridindex, element, ion + 1)); - abort(); - } - } - // printout("\n"); - - // printout("rate %p balance %p NULL %p\n", rate_matrix, balance_vector, (void *)nullptr); - - gsl_matrix_view m = gsl_matrix_view_array(rate_matrix, nlte_size, nlte_size); - gsl_permutation *p = gsl_permutation_alloc(nlte_size); - - int s = 0; // sign of the transformation - gsl_linalg_LU_decomp(&m.matrix, p, &s); - - gsl_vector_view const b = gsl_vector_view_array(balance_vector, nlte_size); - gsl_vector *x = gsl_vector_alloc(nlte_size); - gsl_linalg_LU_solve(&m.matrix, p, &b.vector, x); // solve matrix equation m * x = b for x (populations) - // gsl_linalg_HH_solve (&m.matrix, &b.vector, x); - - // printf("after solving: rate %p balance %p NULL %p\n", rate_matrix, balance_vector, (void *)nullptr); - - printout("The ground state populations were %g, %g, %g and %g\n", get_groundlevelpop(modelgridindex, element, ion), - gsl_vector_get(x, 0), get_groundlevelpop(modelgridindex, element, ion + 1), - gsl_vector_get(x, nlte_size - 1)); - - // printout("The partition functions (and ratios to gs) were: %g (%g) %g (%g)\n", - // grid::modelgrid[modelgridindex].composition[element].partfunct[ion], - // grid::modelgrid[modelgridindex].composition[element].partfunct[ion]/stat_weight(element,ion,0),grid::modelgrid[modelgridindex].composition[element].partfunct[ion+1], - // grid::modelgrid[modelgridindex].composition[element].partfunct[ion+1]/stat_weight(element,ion+1,0)); - - if ((get_groundlevelpop(modelgridindex, element, ion) > (1.1 * MINPOP)) && - (gsl_vector_get(x, 0) > (1.1 * MINPOP))) { - test_ratio = get_groundlevelpop(modelgridindex, element, ion) / gsl_vector_get(x, 0); - if (test_ratio < 1) { - test_ratio = 1. / test_ratio; - } - } else { - test_ratio = 0.0; - } - - double test_ratio_upper = NAN; - if ((get_groundlevelpop(modelgridindex, element, ion + 1) > (1.1 * MINPOP)) && - (gsl_vector_get(x, nlte_size - 1) > (1.1 * MINPOP))) { - test_ratio_upper = get_groundlevelpop(modelgridindex, element, ion + 1) * - grid::modelgrid[modelgridindex].composition[element].partfunct[ion + 1] / - stat_weight(element, ion + 1, 0) / gsl_vector_get(x, nlte_size - 1); - if (test_ratio_upper < 1) { - test_ratio_upper = 1. / test_ratio_upper; - } - } else { - test_ratio_upper = 0.0; - } - - if (test_ratio_upper > test_ratio) { - test_ratio = test_ratio_upper; - } - - printout("The test ratios are %g %g. Passing %g.\n", - get_groundlevelpop(modelgridindex, element, ion) / gsl_vector_get(x, 0), - get_groundlevelpop(modelgridindex, element, ion + 1) * - grid::modelgrid[modelgridindex].composition[element].partfunct[ion + 1] / - stat_weight(element, ion + 1, 0) / gsl_vector_get(x, nlte_size - 1), - test_ratio); - // printout("The test ratio is %g. Passing %g.\n", - // get_groundlevelpop(modelgridindex,element,ion+1)*grid::modelgrid[modelgridindex].composition[element].partfunct[ion+1]/stat_weight(element,ion+1,0)/gsl_vector_get(x,nlte_size-1), - // test_ratio); - - // printout("The top five excited states were %g, %g, %g, %g and - // %g.\n",gsl_vector_get(x,nlevels_nlte-4),gsl_vector_get(x,nlevels_nlte-3),gsl_vector_get(x,nlevels_nlte-2),gsl_vector_get(x,nlevels_nlte-1),gsl_vector_get(x,nlevels_nlte)); - - // printout("The first five excited states were %g, %g, %g, %g and - // %g.\n",gsl_vector_get(x,1),gsl_vector_get(x,2),gsl_vector_get(x,3),gsl_vector_get(x,4),gsl_vector_get(x,5)); - - // lag = 0.0; - - // if ((check=(fabs((1.0 - test_ratio)/(1.0 + test_ratio))) > 0.05) && (check < 0.2)) - //{ - // lag=1.0; - // } - - // Write the NLTE level populations to the array - for (int level = 1; level < nlevels_nlte + 1; level++) { - grid::modelgrid[modelgridindex].nlte_pops[nlte_start + level - 1] = - gsl_vector_get(x, level) / grid::get_rho(modelgridindex); - // printout("I have interfered with index %d.\n", nlte_start+level-1); - // grid::modelgrid[modelgridindex].nlte_pops[nlte_start+level-1] = - // ((lag*grid::modelgrid[modelgridindex].nlte_pops[nlte_start+level-1]) + gsl_vector_get(x,level))/(lag - // + 1.0)/grid::get_rho(modelgridindex); - } - // If there is a superlevel then write that too - - if (super_level) { - // printout("I thought the super level was: %g\n", - // grid::modelgrid[modelgridindex].nlte_pops[nlte_start+nlevels_nlte]); - - grid::modelgrid[modelgridindex].nlte_pops[nlte_start + nlevels_nlte] = - gsl_vector_get(x, nlevels_nlte + 1) / grid::modelgrid[modelgridindex].rho / superlevel_partition; - // grid::modelgrid[modelgridindex].nlte_pops[nlte_start+nlevels_nlte] = - //((lag*grid::modelgrid[modelgridindex].nlte_pops[nlte_start+nlevels_nlte]) + - // gsl_vector_get(x,nlevels_nlte+1))/(lag + 1.0)/grid::modelgrid[modelgridindex].rho/superlevel_partition; - - // printout("Now I think it is: %g\n", grid::modelgrid[modelgridindex].nlte_pops[nlte_start+nlevels_nlte]); - // printout("I also interfered with index %d.\n", nlte_start+nlevels_nlte); - } - - // printout("I had a ground level pop of %g, a part fn of %g and therefore an ion pop of %g\n", - // grid::modelgrid[modelgridindex].composition[element].groundlevelpop[ion], - // grid::modelgrid[modelgridindex].composition[element].partfunct[ion], - // grid::modelgrid[modelgridindex].composition[element].partfunct[ion]*grid::modelgrid[modelgridindex].composition[element].groundlevelpop[ion]/stat_weight(element,ion,0)); - - grid::modelgrid[modelgridindex].composition[element].groundlevelpop[ion] = gsl_vector_get(x, 0); - - // printout("Now I have a ground level pop of %g, a part fn of %g and therefore an ion pop of %g\n", - // grid::modelgrid[modelgridindex].composition[element].groundlevelpop[ion], calculate_partfunct(element, ion, - // modelgridindex), calculate_partfunct(element, ion, - // modelgridindex)*grid::modelgrid[modelgridindex].composition[element].groundlevelpop[ion]/stat_weight(element,ion,0)); - - // printout("For the ion above, I had ground state of %g, a part fn of %g and therefore an ion pop of - // %g\n",grid::modelgrid[modelgridindex].composition[element].groundlevelpop[ion+1], - // grid::modelgrid[modelgridindex].composition[element].partfunct[ion+1], - // grid::modelgrid[modelgridindex].composition[element].partfunct[ion+1]*grid::modelgrid[modelgridindex].composition[element].groundlevelpop[ion+1]/stat_weight(element,ion+1,0)); - - // printout("Now I get that it should have an ion pop of %g\n", gsl_vector_get(x,nlte_size-1)); - - // printout("Accordingly, my phi-factor is: %g\n", calculate_partfunct(element, ion, - // modelgridindex)*grid::modelgrid[modelgridindex].composition[element].groundlevelpop[ion]/stat_weight(element,ion,0)/gsl_vector_get(x,nlte_size-1)/nne); - // printout("The ionization solver gives phi = %g\n", phi(element, ion, modelgridindex)); - - // printout("From ion fract, the lower and upper ion pops should be %g and %g\n", ionfract(element, ion, - // modelgridindex, nne)*nnelement, ionfract(element, ion+1, modelgridindex, nne)*nnelement); printout("I think that - // the element population is: %g (from %g and %g)\n", nnelement, grid::get_elem_abundance(modelgridindex,element), - // grid::get_rho(modelgridindex)); printout("I currently think that the top ion is: %d\n", - // elements_uppermost_ion[tid][element]); - - gsl_permutation_free(p); - // printout("I freed up p\n"); - gsl_vector_free(x); - // printout("I freed up x\n"); - // printf("rate %p balane %p NULL %p\n", rate_matrix, balance_vector,nullptr); - - free(rate_matrix); - // printout("I freed up rate_matrix\n"); - free(balance_vector); - // printout("I freed up balance_vector\n"); - } else { - // STUFF FOR "NOT USING" CASE - - nltepop_reset_element(modelgridindex, element); - test_ratio = 0.0; - } - - return test_ratio; -} - auto superlevel_boltzmann(const int modelgridindex, const int element, const int ion, const int level) -> double { const int superlevel_index = get_nlevels_nlte(element, ion) + 1; const double T_exc = LTEPOP_EXCITATION_USE_TJ ? grid::get_TJ(modelgridindex) : grid::get_Te(modelgridindex); @@ -1584,7 +1102,7 @@ void nltepop_close_file() { } void nltepop_write_to_file(const int modelgridindex, const int timestep) { - if (globals::initial_iteration) { // NLTE solver hasn't been run yet + if (globals::lte_iteration || grid::modelgrid[modelgridindex].thick == 1) { // NLTE solver hasn't been run yet return; } @@ -1639,7 +1157,7 @@ void nltepop_write_to_file(const int modelgridindex, const int timestep) { // grid::modelgrid[modelgridindex].nlte_pops[ion_first_nlte + nlevels_nlte]); } - const double ion_popfrac = nnlevelnlte / ionstagepop(modelgridindex, element, ion); + const double ion_popfrac = nnlevelnlte / get_nnion(modelgridindex, element, ion); fprintf(nlte_file, "%11.5e %11.5e %11.5e\n", nnlevellte, nnlevelnlte, ion_popfrac); } } @@ -1667,10 +1185,8 @@ void nltepop_write_restart_data(FILE *restart_file) { grid::modelgrid[modelgridindex].cooling_contrib_ion[element][ion]); } } - if (NLTE_POPS_ON) { - for (int nlteindex = 0; nlteindex < globals::total_nlte_levels; nlteindex++) { - fprintf(restart_file, "%la ", grid::modelgrid[modelgridindex].nlte_pops[nlteindex]); - } + for (int nlteindex = 0; nlteindex < globals::total_nlte_levels; nlteindex++) { + fprintf(restart_file, "%la ", grid::modelgrid[modelgridindex].nlte_pops[nlteindex]); } } } @@ -1716,15 +1232,13 @@ void nltepop_read_restart_data(FILE *restart_file) { } } } - if (NLTE_POPS_ON) { - for (int nlteindex = 0; nlteindex < globals::total_nlte_levels; nlteindex++) { + for (int nlteindex = 0; nlteindex < globals::total_nlte_levels; nlteindex++) { #ifdef MPI_ON - if (globals::rank_in_node != 0) { - assert_always(fscanf(restart_file, "%*a ") == 0); // discard value (master rank of this node will set it) - } else + if (globals::rank_in_node != 0) { + assert_always(fscanf(restart_file, "%*a ") == 0); // discard value (master rank of this node will set it) + } else #endif - assert_always(fscanf(restart_file, "%la ", &grid::modelgrid[modelgridindex].nlte_pops[nlteindex]) == 1); - } + assert_always(fscanf(restart_file, "%la ", &grid::modelgrid[modelgridindex].nlte_pops[nlteindex]) == 1); } } } \ No newline at end of file diff --git a/nltepop.h b/nltepop.h index b83a4e8c6..6ab5cda90 100644 --- a/nltepop.h +++ b/nltepop.h @@ -4,7 +4,6 @@ #include void solve_nlte_pops_element(int element, int modelgridindex, int timestep, int nlte_iter); -double solve_nlte_pops_ion(int element, int ion, int modelgridindex, int timestep); double superlevel_boltzmann(int modelgridindex, int element, int ion, int level); void nltepop_write_to_file(int modelgridindex, int timestep); void nltepop_open_file(int my_rank); diff --git a/nonthermal.cc b/nonthermal.cc index 76d450656..48e0021b5 100644 --- a/nonthermal.cc +++ b/nonthermal.cc @@ -25,17 +25,17 @@ namespace nonthermal { // THESE OPTIONS ARE USED TO TEST THE SF SOLVER // Compare to Kozma & Fransson (1992) pure-oxygen plasma, nne = 1e8, x_e = 0.01 // #define yscalefactoroverride(mgi) (1e10) -// #define get_tot_nion(x) (1e10) -// #define ionstagepop(modelgridindex, element, ion) ionstagepop_override(modelgridindex, element, ion) +// #define get_nnion_tot(x) (1e10) +// #define get_nnion(modelgridindex, element, ion) get_nnion_override(modelgridindex, element, ion) // #define grid::get_nne(x) (1e8) // #define SFPTS 10000 // number of energy points in the Spencer-Fano solution vector // #define SF_EMAX 3000. // eV // #define SF_EMIN 1. // eV // -// static double ionstagepop_override(const int modelgridindex, const int element, const int ion) +// static double get_nnion_override(const int modelgridindex, const int element, const int ion) // Fake the composition to test the NT solver // { -// const double nntot = get_tot_nion(modelgridindex); +// const double nntot = get_nnion_tot(modelgridindex); // if (get_atomicnumber(element) == 8) // { // const int ion_stage = get_ionstage(element, ion); @@ -47,14 +47,13 @@ namespace nonthermal { // return 0.; // } -#define STORE_NT_SPECTRUM \ - false // if this is on, the non-thermal energy spectrum will be kept in memory for - // every grid cell during packet propagation, which - // can take up a lot of memory for large grid sizes - // alternatively, just the non-thermal ionization rates can be stored - // but we might want to re-enable this option to incorporate - // non-thermal excitation rates if there are - // many more transitions to store than there are NT spectrum samples +constexpr bool STORE_NT_SPECTRUM = false; // if this is on, the non-thermal energy spectrum will be kept in memory for + // every grid cell during packet propagation, which + // can take up a lot of memory for large grid sizes + // alternatively, just the non-thermal ionization rates can be stored + // but we might want to re-enable this option to incorporate + // non-thermal excitation rates if there are + // many more transitions to store than there are NT spectrum samples // minimum number fraction of the total population to include in SF solution constexpr double minionfraction = 1.e-8; @@ -144,38 +143,6 @@ static struct nt_solution_struct *nt_solution; static double *deposition_rate_density; static int *deposition_rate_density_timestep; -// for descending sort -static auto compare_excitation_fractions(const void *p1, const void *p2) -> int { - const auto *elem1 = static_cast(p1); - const auto *elem2 = static_cast(p2); - - if (elem1->frac_deposition < elem2->frac_deposition) { - return 1; - } - if (elem1->frac_deposition > elem2->frac_deposition) { - return -1; - } - return 0; -} - -// for ascending sort -static auto compare_excitation_lineindicies(const void *p1, const void *p2) -> int { - const auto *elem1 = static_cast(p1); - const auto *elem2 = static_cast(p2); - - if (elem1->lineindex > elem2->lineindex) { - return 1; - } - if (elem1->lineindex < elem2->lineindex) { - return -1; - } - return 0; -} - -#ifndef get_tot_nion -static auto get_tot_nion(const int modelgridindex) -> double { return get_nntot(modelgridindex); } -#endif - static void read_binding_energies() { FILE *binding = fopen_required("binding_energies.txt", "r"); @@ -346,7 +313,7 @@ static void read_auger_data() { printout("\n"); // printout("ionpot %g %g, g %d\n", colliondata[i].ionpot_ev, ionpot_ev, g); - bool const found_existing_data = (collionrow.auger_g_accumulated > 0.); + const bool found_existing_data = (collionrow.auger_g_accumulated > 0.); // keep existing data but update according to statistical weight represented by existing and new data const double oldweight = collionrow.auger_g_accumulated / (g + collionrow.auger_g_accumulated); @@ -591,7 +558,7 @@ void calculate_deposition_rate_density(const int modelgridindex, const int times { const double gamma_deposition = globals::rpkt_emiss[modelgridindex] * FOURPI; - const double tmid = globals::time_step[timestep].mid; + const double tmid = globals::timesteps[timestep].mid; const double rho = grid::get_rho(modelgridindex); // TODO: calculate thermalisation ratio from the previous timestep either globally (easy) or per cell @@ -622,13 +589,7 @@ void calculate_deposition_rate_density(const int modelgridindex, const int times auto get_deposition_rate_density(const int modelgridindex) -> double // should be in erg / s / cm^3 { - // if (deposition_rate_density[modelgridindex] <= 0) - // { - // calculate_deposition_rate_density(modelgridindex, nts_global); - // printout("No deposition_rate_density for cell %d. Calculated value of %g has been stored.\n", - // modelgridindex, deposition_rate_density[modelgridindex]); - // } - assert_always(deposition_rate_density_timestep[modelgridindex] == globals::nts_global); + assert_always(deposition_rate_density_timestep[modelgridindex] == globals::timestep); assert_always(deposition_rate_density[modelgridindex] >= 0); return deposition_rate_density[modelgridindex]; } @@ -977,7 +938,7 @@ static auto N_e(const int modelgridindex, const double energy) -> double // not valid for energy > SF_EMIN { const double energy_ev = energy / EV; - const double tot_nion = get_tot_nion(modelgridindex); + const double tot_nion = get_nnion_tot(modelgridindex); double N_e = 0.; for (int element = 0; element < get_nelements(); element++) { @@ -987,7 +948,7 @@ static auto N_e(const int modelgridindex, const double energy) -> double for (int ion = 0; ion < nions; ion++) { double N_e_ion = 0.; const int ionstage = get_ionstage(element, ion); - const double nnion = ionstagepop(modelgridindex, element, ion); + const double nnion = get_nnion(modelgridindex, element, ion); if (nnion < minionfraction * tot_nion) { // skip negligible ions continue; @@ -1017,7 +978,7 @@ static auto N_e(const int modelgridindex, const double energy) -> double } // ionization terms - for (auto &collionrow : colliondata) { + for (const auto &collionrow : colliondata) { if (collionrow.Z == Z && collionrow.nelec == Z - ionstage + 1) { const double ionpot_ev = collionrow.ionpot_ev; const double J = get_J(Z, ionstage, ionpot_ev); @@ -1028,7 +989,7 @@ static auto N_e(const int modelgridindex, const double energy) -> double // integral from ionpot up to lambda for (int i = integral1startindex; i <= integral1stopindex; i++) { - double const endash = gsl_vector_get(envec, i); + const double endash = gsl_vector_get(envec, i); const double delta_endash = DELTA_E; N_e_ion += get_y(modelgridindex, energy_ev + endash) * xs_impactionization(energy_ev + endash, collionrow) * @@ -1038,7 +999,7 @@ static auto N_e(const int modelgridindex, const double energy) -> double // integral from 2E + I up to E_max const int integral2startindex = get_energyindex_ev_lteq(2 * energy_ev + ionpot_ev); for (int i = integral2startindex; i < SFPTS; i++) { - double const endash = gsl_vector_get(envec, i); + const double endash = gsl_vector_get(envec, i); const double delta_endash = DELTA_E; N_e_ion += get_y_sample(modelgridindex, i) * xs_impactionization(endash, collionrow) * Psecondary(endash, energy_ev + ionpot_ev, ionpot_ev, J) * delta_endash; @@ -1272,7 +1233,7 @@ static auto get_oneoverw(const int element, const int ion, const int modelgridin double Zbar = 0.0; // mass-weighted average atomic number for (int ielement = 0; ielement < get_nelements(); ielement++) { - Zbar += grid::modelgrid[modelgridindex].composition[ielement].abundance * globals::elements[ielement].anumber; + Zbar += grid::get_elem_abundance(modelgridindex, ielement) * get_atomicnumber(ielement); } // printout("cell %d has Zbar of %g\n", modelgridindex, Zbar); @@ -1288,7 +1249,7 @@ static auto calculate_nt_frac_ionization_shell(const int modelgridindex, const i const struct collionrow &collionrow) -> double // the fraction of deposition energy that goes into ionising electrons in this particular shell { - const double nnion = ionstagepop(modelgridindex, element, ion); // hopefully ions per cm^3? + const double nnion = get_nnion(modelgridindex, element, ion); // hopefully ions per cm^3? const double ionpot_ev = collionrow.ionpot_ev; gsl_vector *cross_section_vec = gsl_vector_alloc(SFPTS); @@ -1315,7 +1276,7 @@ static auto nt_ionization_ratecoeff_wfapprox(const int modelgridindex, const int // to get the non-thermal ionization rate we need to divide the energy deposited // per unit volume per unit time in the grid cell (sum of terms above) // by the total ion number density and the "work per ion pair" - return deposition_rate_density / get_tot_nion(modelgridindex) * get_oneoverw(element, ion, modelgridindex); + return deposition_rate_density / get_nnion_tot(modelgridindex) * get_oneoverw(element, ion, modelgridindex); } static auto calculate_nt_ionization_ratecoeff(const int modelgridindex, const int element, const int ion, @@ -1378,8 +1339,8 @@ static void calculate_eff_ionpot_auger_rates(const int modelgridindex, const int const int Z = get_atomicnumber(element); const int ionstage = get_ionstage(element, ion); const int uniqueionindex = get_uniqueionindex(element, ion); - const double nnion = ionstagepop(modelgridindex, element, ion); // ions/cm^3 - const double tot_nion = get_tot_nion(modelgridindex); + const double nnion = get_nnion(modelgridindex, element, ion); // ions/cm^3 + const double tot_nion = get_nnion_tot(modelgridindex); const double X_ion = nnion / tot_nion; // molar fraction of this ion // The ionization rates of all shells of an ion add to make the ion's total ionization rate, @@ -1498,7 +1459,7 @@ static void calculate_eff_ionpot_auger_rates(const int modelgridindex, const int } } -static auto get_eff_ionpot(const int modelgridindex, const int element, int const ion) -> float +static auto get_eff_ionpot(const int modelgridindex, const int element, const int ion) -> float // get the effective ion potential from the stored value // a value of 0. should be treated as invalid { @@ -1517,7 +1478,7 @@ static auto nt_ionization_ratecoeff_sf(const int modelgridindex, const int eleme const double deposition_rate_density = get_deposition_rate_density(modelgridindex); if (deposition_rate_density > 0.) { - return deposition_rate_density / get_tot_nion(modelgridindex) / get_eff_ionpot(modelgridindex, element, ion); + return deposition_rate_density / get_nnion_tot(modelgridindex) / get_eff_ionpot(modelgridindex, element, ion); // alternatively, if the y vector is still in memory: // return calculate_nt_ionization_ratecoeff(modelgridindex, element, ion); } @@ -1626,7 +1587,7 @@ auto nt_ionization_ratecoeff(const int modelgridindex, const int element, const assert_always(grid::get_numassociatedcells(modelgridindex) > 0); if (NT_SOLVE_SPENCERFANO) { - double const Y_nt = nt_ionization_ratecoeff_sf(modelgridindex, element, ion); + const double Y_nt = nt_ionization_ratecoeff_sf(modelgridindex, element, ion); if (!std::isfinite(Y_nt)) { // probably because eff_ionpot = 0 because the solver hasn't been run yet, or no impact ionization cross sections // exist @@ -1711,7 +1672,7 @@ auto nt_excitation_ratecoeff(const int modelgridindex, const int element, const // binary search, assuming the excitation list is sorted by lineindex ascending auto ntexclist = nt_solution[modelgridindex].frac_excitations_list; - auto ntexcitation = std::lower_bound(ntexclist.begin(), ntexclist.end(), lineindex, + auto ntexcitation = std::lower_bound(ntexclist.cbegin(), ntexclist.cend(), lineindex, [](const auto &exc, const int lineindex) { return exc.lineindex < lineindex; }); if (ntexcitation == ntexclist.end() || ntexcitation->lineindex != lineindex) { return 0.; @@ -1745,7 +1706,7 @@ static void select_nt_ionization(int modelgridindex, int *element, int *lowerion static auto ion_ntion_energyrate(int modelgridindex, int element, int lowerion) -> double { // returns the energy rate [erg/s] going toward non-thermal ionisation of lowerion - const double nnlowerion = ionstagepop(modelgridindex, element, lowerion); + const double nnlowerion = get_nnion(modelgridindex, element, lowerion); double enrate = 0.; for (int upperion = lowerion + 1; upperion <= nt_ionisation_maxupperion(element, lowerion); upperion++) { const double upperionprobfrac = @@ -1815,9 +1776,6 @@ void do_ntlepton(struct packet *pkt_ptr) { // printout("frac_ionization compare %g and %g\n", frac_ionization, get_nt_frac_ionization(modelgridindex)); // const double frac_ionization = 0.; - // const double frac_excitation = get_nt_frac_excitation(modelgridindex); - const double frac_excitation = 0.; - if (zrand < frac_ionization) { int element = -1; int lowerion = -1; @@ -1854,7 +1812,10 @@ void do_ntlepton(struct packet *pkt_ptr) { return; } - if (NT_EXCITATION_ON && zrand < frac_ionization + frac_excitation) { + + // const double frac_excitation = NT_EXCITATION_ON ? get_nt_frac_excitation(modelgridindex) : 0; + const double frac_excitation = 0.; + if (zrand < (frac_ionization + frac_excitation)) { zrand -= frac_ionization; // now zrand is between zero and frac_excitation // the selection algorithm is the same as for the ionization transitions @@ -1901,7 +1862,7 @@ void do_ntlepton(struct packet *pkt_ptr) { static void analyse_sf_solution(const int modelgridindex, const int timestep, const bool enable_sfexcitation) { const float nne = grid::get_nne(modelgridindex); - const double nntot = get_tot_nion(modelgridindex); + const double nntot = get_nnion_tot(modelgridindex); const double nnetot = grid::get_nnetot(modelgridindex); double frac_excitation_total = 0.; @@ -1916,9 +1877,9 @@ static void analyse_sf_solution(const int modelgridindex, const int timestep, co const int uniqueionindex = get_uniqueionindex(element, ion); const int ionstage = get_ionstage(element, ion); - const double nnion = ionstagepop(modelgridindex, element, ion); + const double nnion = get_nnion(modelgridindex, element, ion); - // if (nnion < minionfraction * get_tot_nion(modelgridindex)) // skip negligible ions + // if (nnion < minionfraction * get_nnion_tot(modelgridindex)) // skip negligible ions if (nnion <= 0.) { // skip zero-abundance ions continue; } @@ -1968,7 +1929,7 @@ static void analyse_sf_solution(const int modelgridindex, const int timestep, co if (!enable_sfexcitation) { nlevels = -1; // disable all excitations } - const bool above_minionfraction = (nnion >= minionfraction * get_tot_nion(modelgridindex)); + const bool above_minionfraction = (nnion >= minionfraction * get_nnion_tot(modelgridindex)); for (int lower = 0; lower < nlevels; lower++) { const double statweight_lower = stat_weight(element, ion, lower); @@ -2067,9 +2028,10 @@ static void analyse_sf_solution(const int modelgridindex, const int timestep, co } if constexpr (NT_EXCITATION_ON && (MAX_NT_EXCITATIONS_STORED > 0)) { - qsort(nt_solution[modelgridindex].frac_excitations_list.data(), - nt_solution[modelgridindex].frac_excitations_list.size(), sizeof(struct nt_excitation_struct), - compare_excitation_fractions); + // sort by descending frac_deposition + std::sort(nt_solution[modelgridindex].frac_excitations_list.begin(), + nt_solution[modelgridindex].frac_excitations_list.end(), + [](const auto &a, const auto &b) { return static_cast(a.frac_deposition > b.frac_deposition); }); // the excitation list is now sorted by frac_deposition descending const double deposition_rate_density = get_deposition_rate_density(modelgridindex); @@ -2106,7 +2068,7 @@ static void analyse_sf_solution(const int modelgridindex, const int timestep, co nt_solution[modelgridindex].frac_excitations_list[excitationindex].ratecoeffperdeposition; const double ntcollexc_ratecoeff = ratecoeffperdeposition * deposition_rate_density; - const double t_mid = globals::time_step[timestep].mid; + const double t_mid = globals::timesteps[timestep].mid; const double radexc_ratecoeff = rad_excitation_ratecoeff(modelgridindex, element, ion, lower, uptransindex, epsilon_trans, lineindex, t_mid); @@ -2124,10 +2086,10 @@ static void analyse_sf_solution(const int modelgridindex, const int timestep, co } } - // now sort the excitation list by lineindex ascending for fast lookup with a binary search - qsort(nt_solution[modelgridindex].frac_excitations_list.data(), - nt_solution[modelgridindex].frac_excitations_list.size(), sizeof(struct nt_excitation_struct), - compare_excitation_lineindicies); + // sort the excitation list by ascending lineindex for fast lookup with a binary search + std::sort(nt_solution[modelgridindex].frac_excitations_list.begin(), + nt_solution[modelgridindex].frac_excitations_list.end(), + [](const auto &a, const auto &b) { return static_cast(a.lineindex < b.lineindex); }); } // NT_EXCITATION_ON @@ -2166,7 +2128,7 @@ static void analyse_sf_solution(const int modelgridindex, const int timestep, co printout(" (replacing calculated frac_heating_tot with %g to make frac_sum = 1.0)\n", nt_solution[modelgridindex].frac_heating); - // const double nnion = ionstagepop(modelgridindex, element, ion); + // const double nnion = get_nnion(modelgridindex, element, ion); // double ntexcit_in_a = 0.; // for (int level = 0; level < get_nlevels(0, 1); level++) // { @@ -2440,7 +2402,7 @@ void solve_spencerfano(const int modelgridindex, const int timestep, const int i const float nne = grid::get_nne(modelgridindex); // electrons per cm^3 // const double nnetot = grid::get_nnetot(modelgridindex); - const double nne_per_ion = nne / get_tot_nion(modelgridindex); + const double nne_per_ion = nne / get_nnion_tot(modelgridindex); const double nne_per_ion_last = nt_solution[modelgridindex].nneperion_when_solved; const double nne_per_ion_fracdiff = fabs((nne_per_ion_last / nne_per_ion) - 1.); const int timestep_last_solved = nt_solution[modelgridindex].timestep_last_solved; @@ -2471,8 +2433,8 @@ void solve_spencerfano(const int modelgridindex, const int timestep, const int i nt_solution[modelgridindex].nneperion_when_solved = nne_per_ion; nt_solution[modelgridindex].timestep_last_solved = timestep; - bool const enable_sfexcitation = true; - bool const enable_sfionization = true; + const bool enable_sfexcitation = true; + const bool enable_sfionization = true; // if (timestep <= globals::num_lte_timesteps) // { // // for the first run of the solver at the first NLTE timestep (which usually requires many iterations), @@ -2522,9 +2484,9 @@ void solve_spencerfano(const int modelgridindex, const int timestep, const int i const int nions = get_nions(element); bool first_included_ion_of_element = true; for (int ion = 0; ion < nions; ion++) { - const double nnion = ionstagepop(modelgridindex, element, ion); // hopefully ions per cm^3? + const double nnion = get_nnion(modelgridindex, element, ion); // hopefully ions per cm^3? - if (nnion < minionfraction * get_tot_nion(modelgridindex)) // skip negligible ions + if (nnion < minionfraction * get_nnion_tot(modelgridindex)) // skip negligible ions { continue; } diff --git a/packet.cc b/packet.cc index 71de54a76..8312e7fd2 100644 --- a/packet.cc +++ b/packet.cc @@ -23,26 +23,46 @@ static void place_pellet(const double e0, const int cellindex, const int pktnumb pkt_ptr->where = cellindex; pkt_ptr->number = pktnumber; /// record the packets number for debugging pkt_ptr->prop_time = globals::tmin; - // pkt_ptr->last_cross = NONE; + // pkt_ptr->last_cross = BOUNDARY_NONE; pkt_ptr->originated_from_particlenotgamma = false; - if (GRID_TYPE == GRID_SPHERICAL1D) { - const double zrand3 = rng_uniform(); + if constexpr (GRID_TYPE == GRID_SPHERICAL1D) { + const double zrand = rng_uniform(); const double r_inner = grid::get_cellcoordmin(cellindex, 0); - const double r_outer = grid::get_cellcoordmin(cellindex, 0) + grid::wid_init(cellindex); - const double radius = pow(zrand3 * pow(r_inner, 3) + (1. - zrand3) * pow(r_outer, 3), 1 / 3.); + const double r_outer = grid::get_cellcoordmax(cellindex, 0); + // use equal volume probability distribution to select radius + const double radius = pow(zrand * pow(r_inner, 3) + (1. - zrand) * pow(r_outer, 3), 1 / 3.); // assert_always(radius >= r_inner); // assert_always(radius <= r_outer); get_rand_isotropic_unitvec(pkt_ptr->pos); vec_scale(pkt_ptr->pos, radius); - } else { + + } else if constexpr (GRID_TYPE == GRID_CYLINDRICAL2D) { + const double zrand1 = rng_uniform(); + const double rcyl_inner = grid::get_cellcoordmin(cellindex, 0); + const double rcyl_outer = grid::get_cellcoordmax(cellindex, 0); + // use equal area probability distribution to select radius + const double rcyl_rand = sqrt(zrand1 * pow(rcyl_inner, 2) + (1. - zrand1) * pow(rcyl_outer, 2)); + const double theta_rand = rng_uniform() * 2 * PI; + pkt_ptr->pos[0] = std::cos(theta_rand) * rcyl_rand; + pkt_ptr->pos[1] = std::sin(theta_rand) * rcyl_rand; + + const double zrand2 = rng_uniform_pos(); + pkt_ptr->pos[2] = grid::get_cellcoordmin(cellindex, 1) + (zrand2 * grid::wid_init(cellindex, 1)); + + } else if constexpr (GRID_TYPE == GRID_CARTESIAN3D) { for (int axis = 0; axis < 3; axis++) { const double zrand = rng_uniform_pos(); - pkt_ptr->pos[axis] = grid::get_cellcoordmin(cellindex, axis) + (zrand * grid::wid_init(0)); + pkt_ptr->pos[axis] = grid::get_cellcoordmin(cellindex, axis) + (zrand * grid::wid_init(cellindex, axis)); } + } else { + assert_always(false); } + // ensure that the random position was inside the cell we selected + assert_always(grid::get_cellindex_from_pos(pkt_ptr->pos, pkt_ptr->prop_time) == cellindex); + const int mgi = grid::get_cell_modelgridindex(cellindex); decay::setup_radioactive_pellet(e0, mgi, pkt_ptr); @@ -52,7 +72,7 @@ static void place_pellet(const double e0, const int cellindex, const int pktnumb // pellet packet is moving with the homologous flow, so dir is proportional to pos vec_norm(pkt_ptr->pos, pkt_ptr->dir); // assign dir = pos / vec_len(pos) - const double dopplerfactor = doppler_packet_nucmf_on_nurf(pkt_ptr); + const double dopplerfactor = doppler_packet_nucmf_on_nurf(pkt_ptr->pos, pkt_ptr->dir, pkt_ptr->prop_time); pkt_ptr->e_rf = pkt_ptr->e_cmf / dopplerfactor; pkt_ptr->trueemissiontype = EMTYPE_NOTSET; @@ -118,9 +138,9 @@ void packet_init(struct packet *pkt) const double targetval = zrand * norm; // first en_cumulative[i] such that en_cumulative[i] > targetval - auto upperval = std::upper_bound(en_cumulative.begin(), en_cumulative.end(), targetval); + auto upperval = std::upper_bound(en_cumulative.cbegin(), en_cumulative.cend(), targetval); assert_always(upperval != en_cumulative.end()); - const ptrdiff_t cellindex = std::distance(en_cumulative.begin(), upperval); + const ptrdiff_t cellindex = std::distance(en_cumulative.cbegin(), upperval); place_pellet(e0, cellindex, n, &pkt[n]); } diff --git a/packet.h b/packet.h index c5c56e083..4c282b833 100644 --- a/packet.h +++ b/packet.h @@ -19,8 +19,6 @@ enum packet_type { constexpr int EMTYPE_NOTSET = -9999000; constexpr int EMTYPE_FREEFREE = -9999999; -#include "boundary.h" - struct mastate { int element; /// macro atom of type element (this is an element index) int ion; /// in ionstage ion (this is an ion index) @@ -28,15 +26,25 @@ struct mastate { int activatingline; /// Linelistindex of the activating line for bb activated MAs, -99 else. }; +enum cell_boundary { + COORD0_MIN = 101, + COORD0_MAX = 102, + COORD1_MIN = 103, + COORD1_MAX = 104, + COORD2_MIN = 105, + COORD2_MAX = 106, + BOUNDARY_NONE = 107, +}; + struct packet { - int where; // The propagation grid cell that the packet is in. - enum packet_type type; // type of packet (k-, r-, etc.) - enum cell_boundary last_cross; // To avoid rounding errors on cell crossing. - int interactions; // number of interactions the packet undergone - int nscatterings; // records number of electron scatterings a r-pkt undergone since it was emitted + int where = -1; // The propagation grid cell that the packet is in. + enum packet_type type; // type of packet (k-, r-, etc.) + enum cell_boundary last_cross = BOUNDARY_NONE; // To avoid rounding errors on cell crossing. + int interactions = 0; // number of interactions the packet undergone + int nscatterings = 0; // records number of electron scatterings a r-pkt undergone since it was emitted int last_event; // debug: stores information about the packets history - double pos[3]; // Position of the packet (x,y,z). - double dir[3]; // Direction of propagation. (x,y,z). Always a unit vector. + double pos[3] = {0}; // Position of the packet (x,y,z). + double dir[3] = {0}; // Direction of propagation. (x,y,z). Always a unit vector. double e_cmf; // The energy the packet carries in the co-moving frame. double e_rf; // The energy the packet carries in the rest frame. double nu_cmf; // The frequency in the co-moving frame. @@ -45,30 +53,30 @@ struct packet { // its linelist index (to overcome numerical problems in propagating the rpkts). int emissiontype = EMTYPE_NOTSET; // records how the packet was emitted if it is a r-pkt double em_pos[3]; // Position of the last emission (x,y,z). - float em_time; - double prop_time; // internal clock to track how far in time the packet has been propagated - int absorptiontype; // records linelistindex of the last absorption - // negative values give ff-abs (-1), bf-abs (-2), compton scattering of gammas (-3), - // photoelectric effect of gammas (-4), pair production of gammas (-5) - // decaying pellets of the 52Fe chain (-6) and pellets which decayed before the - // onset of the simulation (-7) - // decay of a positron pellet (-10) + float em_time = -1.; + double prop_time = -1.; // internal clock to track how far in time the packet has been propagated + int absorptiontype; // records linelistindex of the last absorption + // negative values give ff-abs (-1), bf-abs (-2), compton scattering of gammas (-3), + // photoelectric effect of gammas (-4), pair production of gammas (-5) + // decaying pellets of the 52Fe chain (-6) and pellets which decayed before the + // onset of the simulation (-7) + // decay of a positron pellet (-10) int trueemissiontype = EMTYPE_NOTSET; // emission type coming from a kpkt to rpkt (last thermal emission) - float trueem_time; // first thermal emission time [s] + float trueem_time = -1.; // first thermal emission time [s] double absorptionfreq; // records nu_rf of packet at last absorption - double absorptiondir[3]; // Direction of propagation (x,y,z) when a packet was last absorbed in a line. Always a - // unit vector. - double stokes[3]; // I, Q and U Stokes parameters - double pol_dir[3]; // unit vector which defines the coordinate system against which Q and U are measured; should - // always be perpendicular to dir - double tdecay; // Time at which pellet decays - enum packet_type escape_type; // Flag to tell us in which form it escaped from the grid. - float escape_time; // time at which is passes out of the grid [s] - int number; // A unique number to identify the packet + double absorptiondir[3] = {0.}; // Direction of propagation (x,y,z) when a packet was last absorbed in a line. Always + // a unit vector. + double stokes[3] = {0.}; // I, Q and U Stokes parameters + double pol_dir[3] = {0.}; // unit vector which defines the coordinate system against which Q and U are measured; + // should always be perpendicular to dir + double tdecay = -1.; // Time at which pellet decays + enum packet_type escape_type; // Flag to tell us in which form it escaped from the grid. + float escape_time = -1; // time at which is passes out of the grid [s] + int number = -1; // A unique number to identify the packet bool originated_from_particlenotgamma; // first-non-pellet packet type was gamma - int pellet_decaytype; // index into decay::decaytypes - int pellet_nucindex; // nuclide index of the decaying species - float trueemissionvelocity; + int pellet_decaytype = -1; // index into decay::decaytypes + int pellet_nucindex = -1; // nuclide index of the decaying species + float trueemissionvelocity = -1; struct mastate mastate; inline bool operator==(const packet &rhs) { diff --git a/radfield.cc b/radfield.cc index 972ab5dfd..bb117a7fc 100644 --- a/radfield.cc +++ b/radfield.cc @@ -1,5 +1,6 @@ #include "radfield.h" +#include #include #include #include @@ -7,6 +8,7 @@ #include #include #include +#include #include "atomic.h" #include "grid.h" @@ -17,7 +19,7 @@ namespace radfield { -static double *J_normfactor = nullptr; +static std::vector J_normfactor; // typedef enum // { @@ -51,8 +53,8 @@ MPI_Win win_prev_bfrate_normed = MPI_WIN_NULL; // ** Detailed lines - Jblue_lu estimators for selected lines struct Jb_lu_estimator { - double value; - int contribcount; + double value = 0.; + int contribcount = 0; }; // reallocate the detailed line arrays in units of BLOCKSIZEJBLUE @@ -72,16 +74,16 @@ static double *bfrate_raw = nullptr; // unnormalised estimators for the // expensive debugging mode to track the contributions to each bound-free rate estimator -static double *J = nullptr; // after normalisation: [ergs/s/sr/cm2/Hz] +static std::vector J; // after normalisation: [ergs/s/sr/cm2/Hz] #ifdef DO_TITER -static double *J_reduced_save = nullptr; +static std::vector J_reduced_save; #endif // J and nuJ are accumulated and then normalised in-place // i.e. be sure the normalisation has been applied (exactly once) before using the values here! -static double *nuJ = nullptr; +static std::vector nuJ; #ifdef DO_TITER -static double *nuJ_reduced_save = nullptr; +static std::vector nuJ_reduced_save; #endif using enum_prefactor = enum { @@ -214,18 +216,18 @@ void init(int my_rank, int ndo_nonempty) { const int nonempty_npts_model = grid::get_nonempty_npts_model(); - assert_always(J_normfactor == nullptr); - J_normfactor = static_cast(malloc((grid::get_npts_model() + 1) * sizeof(double))); - J = static_cast(malloc((grid::get_npts_model() + 1) * sizeof(double))); + J_normfactor.resize(nonempty_npts_model + 1); + J.resize(nonempty_npts_model + 1); + #ifdef DO_TITER - J_reduced_save = (double *)malloc((grid::get_npts_model() + 1) * sizeof(double)); + J_reduced_save.resize(nonempty_npts_model + 1); #endif // J and nuJ are accumulated and then normalised in-place // i.e. be sure the normalisation has been applied (exactly once) before using the values here! - nuJ = static_cast(malloc((grid::get_npts_model() + 1) * sizeof(double))); + nuJ.resize(nonempty_npts_model + 1); #ifdef DO_TITER - nuJ_reduced_save = static_cast(malloc((grid::get_npts_model() + 1) * sizeof(double))); + nuJ.resize(nonempty_npts_model + 1); #endif prev_Jb_lu_normed = @@ -396,11 +398,10 @@ void init(int my_rank, int ndo_nonempty) /// Initialise estimator arrays which hold the last time steps values (used to damp out /// fluctuations over timestep iterations if DO_TITER is defined) to -1. void initialise_prev_titer_photoionestimators() { - // for (n = 0; n < ngrid; n++) for (int n = 0; n < grid::get_npts_model(); n++) { -// double T_e = grid::get_Te(n); #ifdef DO_TITER - J_reduced_save[n] = -1.; + const int nonemptymgi = grid::get_modelcell_nonemptymgi(modelgridindex); + J_reduced_save[nonemptymgi] = -1.; #endif #ifdef DO_TITER nuJ_reduced_save[n] = -1.; @@ -411,10 +412,9 @@ void initialise_prev_titer_photoionestimators() { const int nions = get_nions(element); for (int ion = 0; ion < nions - 1; ion++) { #ifdef DO_TITER - globals::gammaestimator_save[n * get_nelements() * get_max_nions() + element * get_max_nions() + ion] = -1.; + globals::gammaestimator_save[get_ionestimindex(n, element, ion)] = -1.; if constexpr (USE_LUT_BFHEATING) { - globals::bfheatingestimator_save[n * get_nelements() * get_max_nions() + element * get_max_nions() + ion] = - -1.; + globals::bfheatingestimator_save[get_ionestimindex(n, element, ion)] = -1.; } #endif } @@ -441,7 +441,7 @@ auto get_Jblueindex(const int lineindex) -> int int low = 0; int high = detailed_linecount; while (low <= high) { - int const mid = low + ((high - low) / 2); + const int mid = low + ((high - low) / 2); if (detailed_lineindicies[mid] < lineindex) { low = mid + 1; } else if (detailed_lineindicies[mid] > lineindex) { @@ -476,21 +476,23 @@ auto get_Jb_lu_contribcount(const int modelgridindex, const int jblueindex) -> i static auto get_bin_J(int modelgridindex, int binindex) -> double // get the normalised J_nu { - assert_testmodeonly(J_normfactor[modelgridindex] > 0.0); + const int nonemptymgi = grid::get_modelcell_nonemptymgi(modelgridindex); + assert_testmodeonly(J_normfactor[nonemptymgi] > 0.0); assert_testmodeonly(modelgridindex < grid::get_npts_model()); assert_testmodeonly(binindex >= 0); assert_testmodeonly(binindex < RADFIELDBINCOUNT); - const int mgibinindex = grid::get_modelcell_nonemptymgi(modelgridindex) * RADFIELDBINCOUNT + binindex; - return radfieldbins[mgibinindex].J_raw * J_normfactor[modelgridindex]; + const int mgibinindex = nonemptymgi * RADFIELDBINCOUNT + binindex; + return radfieldbins[mgibinindex].J_raw * J_normfactor[nonemptymgi]; } static auto get_bin_nuJ(int modelgridindex, int binindex) -> double { - assert_testmodeonly(J_normfactor[modelgridindex] > 0.0); + const int nonemptymgi = grid::get_modelcell_nonemptymgi(modelgridindex); + assert_testmodeonly(J_normfactor[nonemptymgi] > 0.0); assert_testmodeonly(modelgridindex < grid::get_npts_model()); assert_testmodeonly(binindex >= 0); assert_testmodeonly(binindex < RADFIELDBINCOUNT); - const int mgibinindex = grid::get_modelcell_nonemptymgi(modelgridindex) * RADFIELDBINCOUNT + binindex; - return radfieldbins[mgibinindex].nuJ_raw * J_normfactor[modelgridindex]; + const int mgibinindex = nonemptymgi * RADFIELDBINCOUNT + binindex; + return radfieldbins[mgibinindex].nuJ_raw * J_normfactor[nonemptymgi]; } static inline auto get_bin_nu_bar(int modelgridindex, int binindex) -> double @@ -541,7 +543,7 @@ static inline auto select_bin(double nu) -> int { void write_to_file(int modelgridindex, int timestep) { assert_always(MULTIBIN_RADFIELD_MODEL_ON); - + const int nonemptymgi = grid::get_modelcell_nonemptymgi(modelgridindex); #ifdef _OPENMP #pragma omp critical(out_file) { @@ -562,7 +564,7 @@ void write_to_file(int modelgridindex, int timestep) { double J_nu_bar = 0.0; int contribcount = 0; - bool const skipoutput = false; + const bool skipoutput = false; if (binindex >= 0) { nu_lower = get_bin_nu_lower(binindex); @@ -574,8 +576,8 @@ void write_to_file(int modelgridindex, int timestep) { J_nu_bar = J_out / (nu_upper - nu_lower); contribcount = get_bin_contribcount(modelgridindex, binindex); } else if (binindex == -1) { // bin -1 is the full spectrum fit - nuJ_out = nuJ[modelgridindex]; - J_out = J[modelgridindex]; + nuJ_out = nuJ[nonemptymgi]; + J_out = J[nonemptymgi]; T_R = grid::get_TR(modelgridindex); W = grid::get_W(modelgridindex); contribcount = totalcontribs; @@ -647,10 +649,15 @@ void zero_estimators(int modelgridindex) // set up the new bins and clear the estimators in preparation // for a timestep { + if (grid::get_numassociatedcells(modelgridindex) == 0) { + return; + } + + const int nonemptymgi = grid::get_modelcell_nonemptymgi(modelgridindex); + if constexpr (DETAILED_BF_ESTIMATORS_ON) { assert_always(bfrate_raw != nullptr); if (grid::get_numassociatedcells(modelgridindex) > 0) { - const int nonemptymgi = grid::get_modelcell_nonemptymgi(modelgridindex); for (int i = 0; i < globals::nbfcontinua; i++) { bfrate_raw[nonemptymgi * globals::nbfcontinua + i] = 0.; } @@ -666,12 +673,10 @@ void zero_estimators(int modelgridindex) } } - assert_always(J != nullptr); - J[modelgridindex] = 0.; // this is required even if FORCE_LTE is on - assert_always(nuJ != nullptr); - nuJ[modelgridindex] = 0.; + J[nonemptymgi] = 0.; // this is required even if FORCE_LTE is on + nuJ[nonemptymgi] = 0.; - if (MULTIBIN_RADFIELD_MODEL_ON && (grid::get_numassociatedcells(modelgridindex) > 0)) { + if (MULTIBIN_RADFIELD_MODEL_ON) { // printout("radfield: zeroing estimators in %d bins in cell %d\n",RADFIELDBINCOUNT,modelgridindex); assert_always(radfieldbins != nullptr); @@ -685,7 +690,7 @@ void zero_estimators(int modelgridindex) set_J_normfactor(modelgridindex, -1.0); } -static void update_bfestimators(const int modelgridindex, const double distance_e_cmf, const double nu_cmf, +static void update_bfestimators(const int nonemptymgi, const double distance_e_cmf, const double nu_cmf, const struct packet *const pkt_ptr) { assert_testmodeonly(DETAILED_BF_ESTIMATORS_ON); assert_always(bfrate_raw != nullptr); @@ -695,8 +700,7 @@ static void update_bfestimators(const int modelgridindex, const double distance_ } const int nbfcontinua = globals::nbfcontinua; - const double dopplerfactor = doppler_packet_nucmf_on_nurf(pkt_ptr); - const int nonemptymgi = grid::get_modelcell_nonemptymgi(modelgridindex); + const double dopplerfactor = doppler_packet_nucmf_on_nurf(pkt_ptr->pos, pkt_ptr->dir, pkt_ptr->prop_time); // const double dopplerfactor = 1.; const int tid = get_thread_num(); @@ -719,35 +723,20 @@ static void update_bfestimators(const int modelgridindex, const double distance_ void update_estimators(const int modelgridindex, const double distance_e_cmf, const double nu_cmf, const struct packet *const pkt_ptr) { - safeadd(J[modelgridindex], distance_e_cmf); + const int nonemptymgi = grid::get_modelcell_nonemptymgi(modelgridindex); - safeadd(nuJ[modelgridindex], distance_e_cmf * nu_cmf); + safeadd(J[nonemptymgi], distance_e_cmf); + safeadd(nuJ[nonemptymgi], distance_e_cmf * nu_cmf); if constexpr (DETAILED_BF_ESTIMATORS_ON) { - update_bfestimators(modelgridindex, distance_e_cmf, nu_cmf, pkt_ptr); + update_bfestimators(nonemptymgi, distance_e_cmf, nu_cmf, pkt_ptr); } if constexpr (MULTIBIN_RADFIELD_MODEL_ON) { - // int binindex = 0; - // if (nu_cmf <= get_bin_nu_lower(modelgridindex,binindex)) - // { - // printout("radfield: Extending nu_lower_first from %g down to %g\n",nu_lower_first,nu_cmf); - // nu_lower_first = nu_cmf; - // } - // else if (nu_cmf > radfieldbin_nu_upper[modelgridindex][RADFIELDBINCOUNT - 1]) - // { - // binindex = RADFIELDBINCOUNT - 1; - // printout("radfield: Extending nu_upper_last from %g up to - // %g\n",get_bin_nu_upper(modelgridindex,binindex),nu_cmf); get_bin_nu_upper(modelgridindex, binindex) = nu_cmf; - // } - // else - // { - // binindex = select_bin(modelgridindex,nu_cmf); - // } const int binindex = select_bin(nu_cmf); if (binindex >= 0) { - const int mgibinindex = grid::get_modelcell_nonemptymgi(modelgridindex) * RADFIELDBINCOUNT + binindex; + const int mgibinindex = nonemptymgi * RADFIELDBINCOUNT + binindex; safeadd(radfieldbins[mgibinindex].J_raw, distance_e_cmf); safeadd(radfieldbins[mgibinindex].nuJ_raw, distance_e_cmf * nu_cmf); safeincrement(radfieldbins[mgibinindex].contribcount); @@ -763,7 +752,7 @@ void update_estimators(const int modelgridindex, const double distance_e_cmf, co } void update_lineestimator(const int modelgridindex, const int lineindex, const double increment) { - if (!DETAILED_LINE_ESTIMATORS_ON) { + if constexpr (!DETAILED_LINE_ESTIMATORS_ON) { return; } @@ -778,36 +767,18 @@ void update_lineestimator(const int modelgridindex, const int lineindex, const d } } -auto dbb_mgi(double nu, int modelgridindex) -> double { - const float T_R_fullspec = grid::get_TR(modelgridindex); - const float W_fullspec = grid::get_W(modelgridindex); - return dbb(nu, T_R_fullspec, W_fullspec); -} - auto radfield(double nu, int modelgridindex) -> double // returns mean intensity J_nu [ergs/s/sr/cm2/Hz] { if constexpr (MULTIBIN_RADFIELD_MODEL_ON) { - if (globals::nts_global >= FIRST_NLTE_RADFIELD_TIMESTEP) { - // const double lambda = 1e8 * CLIGHT / nu; - // if (lambda < 1085) // Fe II ground state edge - // { - // return dbb(nu, grid::get_TR(modelgridindex), grid::get_W(modelgridindex)); - // } + if (globals::timestep >= FIRST_NLTE_RADFIELD_TIMESTEP) { const int binindex = select_bin(nu); if (binindex >= 0) { const int mgibinindex = grid::get_modelcell_nonemptymgi(modelgridindex) * RADFIELDBINCOUNT + binindex; const struct radfieldbin_solution *const bin = &radfieldbin_solutions[mgibinindex]; if (bin->W >= 0.) { - // if (bin->fit_type == FIT_DILUTE_BLACKBODY) - { - const double J_nu = dbb(nu, bin->T_R, bin->W); - return J_nu; - } - // else - // { - // return bin->W; - // } + const double J_nu = dbb(nu, bin->T_R, bin->W); + return J_nu; } } else { // binindex < 0 // if (nu > get_bin_nu_upper(RADFIELDBINCOUNT - 1)) @@ -856,7 +827,7 @@ static auto planck_integral(double T_R, double nu_lower, double nu_upper, enum_p const gsl_function F_planck = {.function = &gsl_integrand_planck, .params = &intparas}; gsl_error_handler_t *previous_handler = gsl_set_error_handler(gsl_error_handler_printout); - int const status = gsl_integration_qag(&F_planck, nu_lower, nu_upper, epsabs, epsrel, GSLWSIZE, GSL_INTEG_GAUSS61, + const int status = gsl_integration_qag(&F_planck, nu_lower, nu_upper, epsabs, epsrel, GSLWSIZE, GSL_INTEG_GAUSS61, gslworkspace, &integral, &error); if (status != 0) { printout("planck_integral integrator status %d, GSL_FAILURE= %d. Integral value %g, setting to zero.\n", status, @@ -872,31 +843,31 @@ static auto planck_integral_analytic(double T_R, double nu_lower, double nu_uppe double integral = 0.; if (prefactor == TIMES_NU) { - double const debye_upper = gsl_sf_debye_4(HOVERKB * nu_upper / T_R) * pow(nu_upper, 4); - double const debye_lower = gsl_sf_debye_4(HOVERKB * nu_lower / T_R) * pow(nu_lower, 4); + const double debye_upper = gsl_sf_debye_4(HOVERKB * nu_upper / T_R) * pow(nu_upper, 4); + const double debye_lower = gsl_sf_debye_4(HOVERKB * nu_lower / T_R) * pow(nu_lower, 4); integral = TWOHOVERCLIGHTSQUARED * (debye_upper - debye_lower) * T_R / HOVERKB / 4.; } else { - double const debye_upper = gsl_sf_debye_3(HOVERKB * nu_upper / T_R) * pow(nu_upper, 3); - double const debye_lower = gsl_sf_debye_3(HOVERKB * nu_lower / T_R) * pow(nu_lower, 3); + const double debye_upper = gsl_sf_debye_3(HOVERKB * nu_upper / T_R) * pow(nu_upper, 3); + const double debye_lower = gsl_sf_debye_3(HOVERKB * nu_lower / T_R) * pow(nu_lower, 3); integral = TWOHOVERCLIGHTSQUARED * (debye_upper - debye_lower) * T_R / HOVERKB / 3.; if (integral == 0.) { - /*double upperexp = exp(HOVERKB * nu_upper / T_R); - double upperint = - pow(nu_upper,4) / 4 - + pow(nu_upper,3) * log(1 - upperexp) / HOVERKB - + 3 * pow(nu_upper,2) * polylog(2,upperexp) / pow(HOVERKB,2) - - 6 * nu_upper * polylog(3,upperexp) / pow(HOVERKB,3) - + 6 * polylog(4,upperexp) / pow(HOVERKB,4); - double lowerexp = exp(HOVERKB * nu_lower / T_R); - double lowerint = - pow(nu_lower,4) / 4 - + pow(nu_lower,3) * log(1 - lowerexp) / HOVERKB - + 3 * pow(nu_lower,2) * polylog(2,lowerexp) / pow(HOVERKB,2) - - 6 * nu_lower * polylog(3,lowerexp) / pow(HOVERKB,3) - + 6 * polylog(4,lowerexp) / pow(HOVERKB,4); - double integral2 = TWOHOVERCLIGHTSQUARED * (upperint - lowerint); - - printout("planck_integral_analytic is zero. debye_upper %g debye_lower %g. Test alternative %g\n", - debye_upper,debye_lower,integral2);*/ + // double upperexp = exp(HOVERKB * nu_upper / T_R); + // double upperint = - pow(nu_upper,4) / 4 + // + pow(nu_upper,3) * log(1 - upperexp) / HOVERKB + // + 3 * pow(nu_upper,2) * polylog(2,upperexp) / pow(HOVERKB,2) + // - 6 * nu_upper * polylog(3,upperexp) / pow(HOVERKB,3) + // + 6 * polylog(4,upperexp) / pow(HOVERKB,4); + // double lowerexp = exp(HOVERKB * nu_lower / T_R); + // double lowerint = - pow(nu_lower,4) / 4 + // + pow(nu_lower,3) * log(1 - lowerexp) / HOVERKB + // + 3 * pow(nu_lower,2) * polylog(2,lowerexp) / pow(HOVERKB,2) + // - 6 * nu_lower * polylog(3,lowerexp) / pow(HOVERKB,3) + // + 6 * polylog(4,lowerexp) / pow(HOVERKB,4); + // double integral2 = TWOHOVERCLIGHTSQUARED * (upperint - lowerint); + + // printout("planck_integral_analytic is zero. debye_upper %g debye_lower %g. Test alternative %g\n", + // debye_upper,debye_lower,integral2); } } @@ -904,7 +875,7 @@ static auto planck_integral_analytic(double T_R, double nu_lower, double nu_uppe } static auto delta_nu_bar(double T_R, void *paras) -> double -// difference between the average nu and the average nu of a planck function +// difference between the average nu and the average nu of a Planck function // at temperature T_R, in the frequency range corresponding to a bin { const int modelgridindex = (static_cast(paras))->modelgridindex; @@ -944,10 +915,6 @@ static auto delta_nu_bar(double T_R, void *paras) -> double delta_nu_bar, nu_bar_planck_T_R, nu_times_planck_numerical, planck_integral_numerical, nu_bar_estimator); } - // double delta_nu_bar = nu_bar_planck_T_R / nu_bar_estimator - 1.0; - - // printout("delta_nu_bar %g nu_bar_planck %g\n",delta_nu_bar,nu_bar_planck); - return delta_nu_bar; } @@ -1021,12 +988,13 @@ static auto find_T_R(int modelgridindex, int binindex) -> float { } static void set_params_fullspec(const int modelgridindex, const int timestep) { - const double nubar = nuJ[modelgridindex] / J[modelgridindex]; + const int nonemptymgi = grid::get_modelcell_nonemptymgi(modelgridindex); + const double nubar = nuJ[nonemptymgi] / J[nonemptymgi]; if (!std::isfinite(nubar) || nubar == 0.) { printout("[warning] T_R estimator infinite in cell %d, keep T_R, T_J, W of last timestep. J = %g. nuJ = %g\n", - modelgridindex, J[modelgridindex], nuJ[modelgridindex]); + modelgridindex, J[nonemptymgi], nuJ[nonemptymgi]); } else { - float T_J = pow(J[modelgridindex] * PI / STEBO, 1 / 4.); + float T_J = pow(J[nonemptymgi] * PI / STEBO, 1 / 4.); if (T_J > MAXTEMP) { printout("[warning] temperature estimator T_J = %g exceeds T_max %g in cell %d. Setting T_J = T_max!\n", T_J, MAXTEMP, modelgridindex); @@ -1050,12 +1018,12 @@ static void set_params_fullspec(const int modelgridindex, const int timestep) { } grid::set_TR(modelgridindex, T_R); - const float W = J[modelgridindex] * PI / STEBO / pow(T_R, 4); + const float W = J[nonemptymgi] * PI / STEBO / pow(T_R, 4); grid::set_W(modelgridindex, W); printout( "Full-spectrum fit radfield for cell %d at timestep %d: J %g, nubar %5.1f Angstrom, T_J %g, T_R %g, W %g\n", - modelgridindex, timestep, J[modelgridindex], 1e8 * CLIGHT / nubar, T_J, T_R, W); + modelgridindex, timestep, J[nonemptymgi], 1e8 * CLIGHT / nubar, T_J, T_R, W); } } @@ -1065,9 +1033,11 @@ void fit_parameters(int modelgridindex, int timestep) { set_params_fullspec(modelgridindex, timestep); + const int nonemptymgi = grid::get_modelcell_nonemptymgi(modelgridindex); + if constexpr (MULTIBIN_RADFIELD_MODEL_ON) { - if (J_normfactor[modelgridindex] <= 0) { - printout("radfield: FATAL J_normfactor = %g in cell %d at call to fit_parameters", J_normfactor[modelgridindex], + if (J_normfactor[nonemptymgi] <= 0) { + printout("radfield: FATAL J_normfactor = %g in cell %d at call to fit_parameters", J_normfactor[nonemptymgi], modelgridindex); abort(); } @@ -1077,15 +1047,13 @@ void fit_parameters(int modelgridindex, int timestep) J_bin_sum += get_bin_J(modelgridindex, binindex); } - printout("radfield bins sum to J of %g (%.1f%% of total J).\n", J_bin_sum, 100. * J_bin_sum / J[modelgridindex]); + printout("radfield bins sum to J of %g (%.1f%% of total J).\n", J_bin_sum, 100. * J_bin_sum / J[nonemptymgi]); printout("radfield: Finding parameters for %d bins...\n", RADFIELDBINCOUNT); double J_bin_max = 0.; for (int binindex = 0; binindex < RADFIELDBINCOUNT; binindex++) { const double J_bin = get_bin_J(modelgridindex, binindex); - if (J_bin > J_bin_max) { - J_bin_max = J_bin; - } + J_bin_max = std::max(J_bin_max, J_bin); } for (int binindex = 0; binindex < RADFIELDBINCOUNT; binindex++) { @@ -1151,7 +1119,7 @@ void fit_parameters(int modelgridindex, int timestep) // T_R_bin = -1; // W_bin = -1; // } - const int mgibinindex = grid::get_modelcell_nonemptymgi(modelgridindex) * RADFIELDBINCOUNT + binindex; + const int mgibinindex = nonemptymgi * RADFIELDBINCOUNT + binindex; radfieldbin_solutions[mgibinindex].T_R = T_R_bin; radfieldbin_solutions[mgibinindex].W = W_bin; } @@ -1178,11 +1146,15 @@ void fit_parameters(int modelgridindex, int timestep) } } -void set_J_normfactor(int modelgridindex, double normfactor) { J_normfactor[modelgridindex] = normfactor; } +void set_J_normfactor(int modelgridindex, double normfactor) { + const int nonemptymgi = grid::get_modelcell_nonemptymgi(modelgridindex); + J_normfactor[nonemptymgi] = normfactor; +} void normalise_J(const int modelgridindex, const double estimator_normfactor_over4pi) { - assert_always(std::isfinite(J[modelgridindex])); - J[modelgridindex] *= estimator_normfactor_over4pi; + const int nonemptymgi = grid::get_modelcell_nonemptymgi(modelgridindex); + assert_always(std::isfinite(J[nonemptymgi])); + J[nonemptymgi] *= estimator_normfactor_over4pi; for (int i = 0; i < detailed_linecount; i++) { prev_Jb_lu_normed[modelgridindex][i].value = Jb_lu_raw[modelgridindex][i].value * estimator_normfactor_over4pi; prev_Jb_lu_normed[modelgridindex][i].contribcount = Jb_lu_raw[modelgridindex][i].contribcount; @@ -1204,13 +1176,16 @@ void normalise_bf_estimators(const int modelgridindex, const double estimator_no static auto get_bfcontindex(const int element, const int lowerion, const int lower, const int phixstargetindex) -> int { // simple linear search seems to be faster than the binary search // possibly because lower frequency transitions near start of list are more likely to be called? - for (int i = 0; i < globals::nbfcontinua; i++) { - if ((globals::allcont[i].element == element) && (globals::allcont[i].ion == lowerion) && - (globals::allcont[i].level == lower) && (globals::allcont[i].phixstargetindex == phixstargetindex)) { - return i; - } - } + const auto &matchbf = std::find_if(globals::allcont, globals::allcont + globals::nbfcontinua, [=](const auto &bf) { + return (bf.element == element) && (bf.ion == lowerion) && (bf.level == lower) && + (bf.phixstargetindex == phixstargetindex); + }); + + const int bfcontindex = std::distance(globals::allcont, matchbf); + if (bfcontindex < globals::nbfcontinua) { + return bfcontindex; + } // not found in the continua list return -1; } @@ -1233,12 +1208,14 @@ auto get_bfrate_estimator(const int element, const int lowerion, const int lower } void normalise_nuJ(const int modelgridindex, const double estimator_normfactor_over4pi) { - assert_always(std::isfinite(nuJ[modelgridindex])); - nuJ[modelgridindex] *= estimator_normfactor_over4pi; + const int nonemptymgi = grid::get_modelcell_nonemptymgi(modelgridindex); + assert_always(std::isfinite(nuJ[nonemptymgi])); + nuJ[nonemptymgi] *= estimator_normfactor_over4pi; } auto get_T_J_from_J(const int modelgridindex) -> double { - const double T_J = pow(J[modelgridindex] * PI / STEBO, 1. / 4.); + const int nonemptymgi = grid::get_modelcell_nonemptymgi(modelgridindex); + const double T_J = pow(J[nonemptymgi] * PI / STEBO, 1. / 4.); if (!std::isfinite(T_J)) { /// keep old value of T_J printout("[warning] get_T_J_from_J: T_J estimator infinite in cell %d, use value of last timestep\n", @@ -1259,17 +1236,19 @@ auto get_T_J_from_J(const int modelgridindex) -> double { #ifdef DO_TITER void titer_J(const int modelgridindex) { - if (J_reduced_save[modelgridindex] >= 0) { - J[modelgridindex] = (J[modelgridindex] + J_reduced_save[modelgridindex]) / 2; + const int nonemptymgi = grid::get_modelcell_nonemptymgi(modelgridindex); + if (J_reduced_save[nonemptymgi] >= 0) { + J[nonemptymgi] = (J[nonemptymgi] + J_reduced_save[nonemptymgi]) / 2; } - J_reduced_save[modelgridindex] = J[modelgridindex]; + J_reduced_save[nonemptymgi] = J[nonemptymgi]; } void titer_nuJ(const int modelgridindex) { - if (nuJ_reduced_save[modelgridindex] >= 0) { - nuJ[modelgridindex] = (nuJ[modelgridindex] + nuJ_reduced_save[modelgridindex]) / 2; + const int nonemptymgi = grid::get_modelcell_nonemptymgi(modelgridindex); + if (nuJ_reduced_save[nonemptymgi] >= 0) { + nuJ[nonemptymgi] = (nuJ[nonemptymgi] + nuJ_reduced_save[nonemptymgi]) / 2; } - nuJ_reduced_save[modelgridindex] = nuJ[modelgridindex]; + nuJ_reduced_save[nonemptymgi] = nuJ[nonemptymgi]; } #endif @@ -1277,11 +1256,13 @@ void titer_nuJ(const int modelgridindex) { void reduce_estimators() // reduce and broadcast (allreduce) the estimators for J and nuJ in all bins { - MPI_Allreduce(MPI_IN_PLACE, J, grid::get_npts_model(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(MPI_IN_PLACE, nuJ, grid::get_npts_model(), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + const int nonempty_npts_model = grid::get_nonempty_npts_model(); + + MPI_Allreduce(MPI_IN_PLACE, J.data(), nonempty_npts_model, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(MPI_IN_PLACE, nuJ.data(), nonempty_npts_model, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); if constexpr (DETAILED_BF_ESTIMATORS_ON) { - MPI_Allreduce(MPI_IN_PLACE, bfrate_raw, grid::get_nonempty_npts_model() * globals::nbfcontinua, MPI_DOUBLE, MPI_SUM, + MPI_Allreduce(MPI_IN_PLACE, bfrate_raw, nonempty_npts_model * globals::nbfcontinua, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); } @@ -1290,22 +1271,12 @@ void reduce_estimators() printout("Reducing binned radiation field estimators"); assert_always(radfieldbins != nullptr); - for (int modelgridindex = 0; modelgridindex < grid::get_npts_model(); modelgridindex++) { - // printout("DEBUGCELLS: cell %d associated_cells %d\n", modelgridindex, - // grid::get_numassociatedcells(modelgridindex)); - if (grid::get_numassociatedcells(modelgridindex) > 0) { - const int nonemptymgi = grid::get_modelcell_nonemptymgi(modelgridindex); - for (int binindex = 0; binindex < RADFIELDBINCOUNT; binindex++) { - const int mgibinindex = nonemptymgi * RADFIELDBINCOUNT + binindex; - // printout("MPI: pre-MPI_Allreduce, this process modelgrid %d binindex %d has a individual contribcount of - // %d\n",modelgridindex,binindex,radfieldbins[mgibinindex].contribcount); - MPI_Allreduce(MPI_IN_PLACE, &radfieldbins[mgibinindex].J_raw, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(MPI_IN_PLACE, &radfieldbins[mgibinindex].nuJ_raw, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(MPI_IN_PLACE, &radfieldbins[mgibinindex].contribcount, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD); - - // printout("MPI: After MPI_Allreduce: this process modelgrid %d binindex %d has a contribcount of - // %d\n",modelgridindex,binindex,radfieldbins[mgibinindex].contribcount); - } + for (int nonemptymgi = 0; nonemptymgi < nonempty_npts_model; nonemptymgi++) { + for (int binindex = 0; binindex < RADFIELDBINCOUNT; binindex++) { + const int mgibinindex = nonemptymgi * RADFIELDBINCOUNT + binindex; + MPI_Allreduce(MPI_IN_PLACE, &radfieldbins[mgibinindex].J_raw, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(MPI_IN_PLACE, &radfieldbins[mgibinindex].nuJ_raw, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(MPI_IN_PLACE, &radfieldbins[mgibinindex].contribcount, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD); } } const int duration_reduction = time(nullptr) - sys_time_start_reduction; @@ -1317,8 +1288,6 @@ void reduce_estimators() printout("Reducing detailed line estimators"); for (int modelgridindex = 0; modelgridindex < grid::get_npts_model(); modelgridindex++) { - // printout("DEBUGCELLS: cell %d associated_cells %d\n", modelgridindex, - // grid::get_numassociatedcells(modelgridindex)); if (grid::get_numassociatedcells(modelgridindex) > 0) { for (int jblueindex = 0; jblueindex < detailed_linecount; jblueindex++) { MPI_Allreduce(MPI_IN_PLACE, &Jb_lu_raw[modelgridindex][jblueindex].value, 1, MPI_DOUBLE, MPI_SUM, @@ -1338,36 +1307,40 @@ void do_MPI_Bcast(const int modelgridindex, const int root, int root_node_id) // broadcast computed radfield results including parameters // from the cells belonging to root process to all processes { - MPI_Bcast(&J_normfactor[modelgridindex], 1, MPI_DOUBLE, root, MPI_COMM_WORLD); - if (grid::get_numassociatedcells(modelgridindex) > 0) { - const int nonemptymgi = grid::get_modelcell_nonemptymgi(modelgridindex); - if constexpr (MULTIBIN_RADFIELD_MODEL_ON) { - for (int binindex = 0; binindex < RADFIELDBINCOUNT; binindex++) { - const int mgibinindex = nonemptymgi * RADFIELDBINCOUNT + binindex; - if (globals::rank_in_node == 0) { - MPI_Bcast(&radfieldbin_solutions[mgibinindex].W, 1, MPI_FLOAT, root_node_id, globals::mpi_comm_internode); - MPI_Bcast(&radfieldbin_solutions[mgibinindex].T_R, 1, MPI_FLOAT, root_node_id, globals::mpi_comm_internode); - } - MPI_Bcast(&radfieldbins[mgibinindex].J_raw, 1, MPI_DOUBLE, root, MPI_COMM_WORLD); - MPI_Bcast(&radfieldbins[mgibinindex].nuJ_raw, 1, MPI_DOUBLE, root, MPI_COMM_WORLD); - MPI_Bcast(&radfieldbins[mgibinindex].contribcount, 1, MPI_INT, root, MPI_COMM_WORLD); - } - } + if (grid::get_numassociatedcells(modelgridindex) == 0) { + return; + } + + const int nonemptymgi = grid::get_modelcell_nonemptymgi(modelgridindex); + MPI_Bcast(&J_normfactor[nonemptymgi], 1, MPI_DOUBLE, root, MPI_COMM_WORLD); - if constexpr (DETAILED_BF_ESTIMATORS_ON) { + if constexpr (MULTIBIN_RADFIELD_MODEL_ON) { + for (int binindex = 0; binindex < RADFIELDBINCOUNT; binindex++) { + const int mgibinindex = nonemptymgi * RADFIELDBINCOUNT + binindex; if (globals::rank_in_node == 0) { - MPI_Bcast(&prev_bfrate_normed[nonemptymgi * globals::nbfcontinua], globals::nbfcontinua, MPI_FLOAT, - root_node_id, globals::mpi_comm_internode); + MPI_Bcast(&radfieldbin_solutions[mgibinindex].W, 1, MPI_FLOAT, root_node_id, globals::mpi_comm_internode); + MPI_Bcast(&radfieldbin_solutions[mgibinindex].T_R, 1, MPI_FLOAT, root_node_id, globals::mpi_comm_internode); } + MPI_Bcast(&radfieldbins[mgibinindex].J_raw, 1, MPI_DOUBLE, root, MPI_COMM_WORLD); + MPI_Bcast(&radfieldbins[mgibinindex].nuJ_raw, 1, MPI_DOUBLE, root, MPI_COMM_WORLD); + MPI_Bcast(&radfieldbins[mgibinindex].contribcount, 1, MPI_INT, root, MPI_COMM_WORLD); } + } - if (DETAILED_LINE_ESTIMATORS_ON) { - for (int jblueindex = 0; jblueindex < detailed_linecount; jblueindex++) { - MPI_Bcast(&prev_Jb_lu_normed[modelgridindex][jblueindex].value, 1, MPI_DOUBLE, root, MPI_COMM_WORLD); - MPI_Bcast(&prev_Jb_lu_normed[modelgridindex][jblueindex].contribcount, 1, MPI_INT, root, MPI_COMM_WORLD); - } + if constexpr (DETAILED_BF_ESTIMATORS_ON) { + if (globals::rank_in_node == 0) { + MPI_Bcast(&prev_bfrate_normed[nonemptymgi * globals::nbfcontinua], globals::nbfcontinua, MPI_FLOAT, root_node_id, + globals::mpi_comm_internode); + } + } + + if constexpr (DETAILED_LINE_ESTIMATORS_ON) { + for (int jblueindex = 0; jblueindex < detailed_linecount; jblueindex++) { + MPI_Bcast(&prev_Jb_lu_normed[modelgridindex][jblueindex].value, 1, MPI_DOUBLE, root, MPI_COMM_WORLD); + MPI_Bcast(&prev_Jb_lu_normed[modelgridindex][jblueindex].contribcount, 1, MPI_INT, root, MPI_COMM_WORLD); } } + MPI_Barrier(MPI_COMM_WORLD); } #endif @@ -1413,7 +1386,7 @@ void write_restart_data(FILE *gridsave_file) { if (grid::get_numassociatedcells(modelgridindex) > 0) { const int nonemptymgi = grid::get_modelcell_nonemptymgi(modelgridindex); assert_testmodeonly(nonemptymgi >= 0); - fprintf(gridsave_file, "%d %la\n", modelgridindex, J_normfactor[modelgridindex]); + fprintf(gridsave_file, "%d %la\n", modelgridindex, J_normfactor[nonemptymgi]); if constexpr (MULTIBIN_RADFIELD_MODEL_ON) { for (int binindex = 0; binindex < RADFIELDBINCOUNT; binindex++) { @@ -1510,7 +1483,7 @@ void read_restart_data(FILE *gridsave_file) { } } - if (DETAILED_LINE_ESTIMATORS_ON) { + if constexpr (DETAILED_LINE_ESTIMATORS_ON) { int detailed_linecount_in = 0; assert_always(fscanf(gridsave_file, "%d\n", &detailed_linecount_in) == 1); @@ -1529,7 +1502,7 @@ void read_restart_data(FILE *gridsave_file) { if (grid::get_numassociatedcells(modelgridindex) > 0) { const int nonemptymgi = grid::get_modelcell_nonemptymgi(modelgridindex); int mgi_in = 0; - assert_always(fscanf(gridsave_file, "%d %la\n", &mgi_in, &J_normfactor[modelgridindex]) == 2); + assert_always(fscanf(gridsave_file, "%d %la\n", &mgi_in, &J_normfactor[nonemptymgi]) == 2); if (mgi_in != modelgridindex) { printout("ERROR: expected data for cell %d but found cell %d\n", modelgridindex, mgi_in); abort(); @@ -1572,10 +1545,10 @@ void read_restart_data(FILE *gridsave_file) { // across the binned radiation field which is discontinuous at the bin boundaries inline auto integrate(const gsl_function *f, double nu_a, double nu_b, double epsabs, double epsrel, size_t limit, int key, gsl_integration_workspace *workspace, double *result, double *abserr) -> int { - if (MULTIBIN_RADFIELD_MODEL_ON && (globals::nts_global >= FIRST_NLTE_RADFIELD_TIMESTEP)) { + if (MULTIBIN_RADFIELD_MODEL_ON && (globals::timestep >= FIRST_NLTE_RADFIELD_TIMESTEP)) { auto *pts = static_cast(malloc((RADFIELDBINCOUNT + 3) * sizeof(double))); int binindex_a = select_bin(nu_a); - int const binindex_b = select_bin(nu_b); + const int binindex_b = select_bin(nu_b); int npts = 0; pts[npts++] = nu_a; if (binindex_a == binindex_b) // both higher, both lower, or match the same bin diff --git a/radfield.h b/radfield.h index 59cea7938..690f842c6 100644 --- a/radfield.h +++ b/radfield.h @@ -8,6 +8,7 @@ #include "sn3d.h" namespace radfield { + void zero_estimators(int modelgridindex); void init(int my_rank, int ndo_nonempty); void initialise_prev_titer_photoionestimators(); @@ -16,7 +17,6 @@ void close_file(); void update_estimators(int modelgridindex, double distance_e_cmf, double nu_cmf, const struct packet *pkt_ptr); void update_lineestimator(int modelgridindex, int lineindex, double increment); double radfield(double nu, int modelgridindex); -double dbb_mgi(double nu, int modelgridindex); void fit_parameters(int modelgridindex, int timestep); void set_J_normfactor(int modelgridindex, double normfactor); void normalise_J(int modelgridindex, double estimator_normfactor_over4pi); @@ -39,9 +39,8 @@ void reset_bfrate_contributions(int modelgridindex); int integrate(const gsl_function *f, double nu_a, double nu_b, double epsabs, double epsrel, size_t limit, int key, gsl_integration_workspace *workspace, double *result, double *abserr); -template -constexpr double dbb(double nu, T_t T, W_t W) -// returns J_nu for a dilute black body [ergs/s/sr/cm2/Hz] +constexpr double dbb(double nu, auto T, auto W) +// returns J_nu [ergs/s/sr/cm2/Hz] for a dilute black body with temperature T and dilution factor W { return W * TWOHOVERCLIGHTSQUARED * std::pow(nu, 3) / std::expm1(HOVERKB * nu / T); } diff --git a/ratecoeff.cc b/ratecoeff.cc index e054452e7..a81ec589d 100644 --- a/ratecoeff.cc +++ b/ratecoeff.cc @@ -5,8 +5,9 @@ #include #include #include -// #define _XOPEN_SOURCE #define D_POSIX_SOURCE +#include + #include #include "artisoptions.h" @@ -31,9 +32,15 @@ // int cellnumber; // } gslintegration_bfheatingparas; -static double T_step; double T_step_log; +static double *spontrecombcoeffs = nullptr; + +// for USE_LUT_PHOTOION = true +static double *corrphotoioncoeffs = nullptr; + +static double *bfcooling_coeffs = nullptr; + using gsl_integral_paras_gammacorr = struct { double nu_edge; double departure_ratio; @@ -46,6 +53,65 @@ static char adatafile_hash[33]; static char compositionfile_hash[33]; std::array phixsfile_hash; +void setup_photoion_luts() { + size_t mem_usage_photoionluts = 2 * TABLESIZE * globals::nbfcontinua * sizeof(double); + + if (globals::nbfcontinua > 0) { +#ifdef MPI_ON + MPI_Win win = MPI_WIN_NULL; + MPI_Aint size = (globals::rank_in_node == 0) ? TABLESIZE * globals::nbfcontinua * sizeof(double) : 0; + int disp_unit = sizeof(double); + assert_always(MPI_Win_allocate_shared(size, disp_unit, MPI_INFO_NULL, globals::mpi_comm_node, &spontrecombcoeffs, + &win) == MPI_SUCCESS); + assert_always(MPI_Win_shared_query(win, 0, &size, &disp_unit, &spontrecombcoeffs) == MPI_SUCCESS); +#else + spontrecombcoeffs = static_cast(malloc(TABLESIZE * globals::nbfcontinua * sizeof(double))); +#endif + assert_always(spontrecombcoeffs != nullptr); + + if constexpr (USE_LUT_PHOTOION) { +#ifdef MPI_ON + size = (globals::rank_in_node == 0) ? TABLESIZE * globals::nbfcontinua * sizeof(double) : 0; + assert_always(MPI_Win_allocate_shared(size, disp_unit, MPI_INFO_NULL, globals::mpi_comm_node, &corrphotoioncoeffs, + &win) == MPI_SUCCESS); + assert_always(MPI_Win_shared_query(win, 0, &size, &disp_unit, &corrphotoioncoeffs) == MPI_SUCCESS); +#else + corrphotoioncoeffs = static_cast(malloc(TABLESIZE * globals::nbfcontinua * sizeof(double))); +#endif + assert_always(corrphotoioncoeffs != nullptr); + mem_usage_photoionluts += TABLESIZE * globals::nbfcontinua * sizeof(double); + } + + if constexpr (USE_LUT_BFHEATING) { +#ifdef MPI_ON + size = (globals::rank_in_node == 0) ? TABLESIZE * globals::nbfcontinua * sizeof(double) : 0; + assert_always(MPI_Win_allocate_shared(size, disp_unit, MPI_INFO_NULL, globals::mpi_comm_node, + &globals::bfheating_coeff, &win) == MPI_SUCCESS); + assert_always(MPI_Win_shared_query(win, 0, &size, &disp_unit, &globals::bfheating_coeff) == MPI_SUCCESS); +#else + globals::bfheating_coeff = static_cast(malloc(TABLESIZE * globals::nbfcontinua * sizeof(double))); +#endif + assert_always(globals::bfheating_coeff != nullptr); + mem_usage_photoionluts += TABLESIZE * globals::nbfcontinua * sizeof(double); + } + +#ifdef MPI_ON + size = (globals::rank_in_node == 0) ? TABLESIZE * globals::nbfcontinua * sizeof(double) : 0; + assert_always(MPI_Win_allocate_shared(size, disp_unit, MPI_INFO_NULL, globals::mpi_comm_node, &bfcooling_coeffs, + &win) == MPI_SUCCESS); + assert_always(MPI_Win_shared_query(win, 0, &size, &disp_unit, &bfcooling_coeffs) == MPI_SUCCESS); +#else + bfcooling_coeffs = static_cast(malloc(TABLESIZE * globals::nbfcontinua * sizeof(double))); +#endif + assert_always(bfcooling_coeffs != nullptr); + } + + printout( + "[info] mem_usage: lookup tables derived from photoionisation (spontrecombcoeff, bfcooling and " + "corrphotoioncoeff/bfheating if enabled) occupy %.3f MB\n", + mem_usage_photoionluts / 1024. / 1024.); +} + static auto read_ratecoeff_dat(FILE *ratecoeff_file) -> bool /// Try to read in the precalculated rate coefficients from file /// return true if successful or false otherwise @@ -145,7 +211,7 @@ static auto read_ratecoeff_dat(FILE *ratecoeff_file) -> bool assert_always( fscanf(ratecoeff_file, "%d %d %d %d\n", &in_element, &in_ionstage, &in_levels, &in_ionisinglevels) == 4); const int nlevels = get_nlevels(element, ion); - int const ionisinglevels = get_ionisinglevels(element, ion); + const int ionisinglevels = get_ionisinglevels(element, ion); if (get_atomicnumber(element) != in_element || get_ionstage(element, ion) != in_ionstage || nlevels != in_levels || ionisinglevels != in_ionisinglevels) { printout( @@ -160,7 +226,7 @@ static auto read_ratecoeff_dat(FILE *ratecoeff_file) -> bool printout("Existing ratecoeff.dat is valid. Reading this file...\n"); for (int element = 0; element < get_nelements(); element++) { - int const nions = get_nions(element) - 1; + const int nions = get_nions(element) - 1; for (int ion = 0; ion < nions; ion++) { // nlevels = get_nlevels(element,ion); const int nlevels = get_ionisinglevels(element, ion); /// number of ionising levels associated with current ion @@ -172,23 +238,22 @@ static auto read_ratecoeff_dat(FILE *ratecoeff_file) -> bool for (int phixstargetindex = 0; phixstargetindex < nphixstargets; phixstargetindex++) { /// Loop over the temperature grid for (int iter = 0; iter < TABLESIZE; iter++) { - double alpha_sp = NAN; - double bfcooling_coeff = NAN; - double corrphotoioncoeff = NAN; - double bfheating_coeff = NAN; - assert_always(fscanf(ratecoeff_file, "%la %la %la %la\n", &alpha_sp, &bfcooling_coeff, &corrphotoioncoeff, - &bfheating_coeff) == 4); + double in_alpha_sp = NAN; + double in_bfcooling_coeff = NAN; + double in_corrphotoioncoeff = NAN; + double in_bfheating_coeff = NAN; + assert_always(fscanf(ratecoeff_file, "%la %la %la %la\n", &in_alpha_sp, &in_bfcooling_coeff, + &in_corrphotoioncoeff, &in_bfheating_coeff) == 4); // assert_always(std::isfinite(alpha_sp) && alpha_sp >= 0); - globals::spontrecombcoeff[get_bflutindex(iter, element, ion, level, phixstargetindex)] = alpha_sp; + spontrecombcoeffs[get_bflutindex(iter, element, ion, level, phixstargetindex)] = in_alpha_sp; // assert_always(std::isfinite(bfcooling_coeff) && bfcooling_coeff >= 0); - globals::bfcooling_coeff[get_bflutindex(iter, element, ion, level, phixstargetindex)] = bfcooling_coeff; + bfcooling_coeffs[get_bflutindex(iter, element, ion, level, phixstargetindex)] = in_bfcooling_coeff; if constexpr (USE_LUT_PHOTOION) { - if (corrphotoioncoeff >= 0) { - globals::corrphotoioncoeff[get_bflutindex(iter, element, ion, level, phixstargetindex)] = - corrphotoioncoeff; + if (in_corrphotoioncoeff >= 0) { + corrphotoioncoeffs[get_bflutindex(iter, element, ion, level, phixstargetindex)] = in_corrphotoioncoeff; } else { printout( "ERROR: USE_LUT_PHOTOION is on, but there are no corrphotoioncoeff values in ratecoeff file\n"); @@ -196,8 +261,9 @@ static auto read_ratecoeff_dat(FILE *ratecoeff_file) -> bool } } if constexpr (USE_LUT_BFHEATING) { - if (bfheating_coeff >= 0) { - globals::bfheating_coeff[get_bflutindex(iter, element, ion, level, phixstargetindex)] = bfheating_coeff; + if (in_bfheating_coeff >= 0) { + globals::bfheating_coeff[get_bflutindex(iter, element, ion, level, phixstargetindex)] = + in_bfheating_coeff; } else { printout( "ERROR: USE_LUT_BFHEATING is on, but there are no bfheating_coeff values in the ratecoeff " @@ -243,13 +309,10 @@ static void write_ratecoeff_dat() { /// Loop over the temperature grid for (int iter = 0; iter < TABLESIZE; iter++) { const int bflutindex = get_bflutindex(iter, element, ion, level, phixstargetindex); - const double alpha_sp = globals::spontrecombcoeff[bflutindex]; - const double bfcooling_coeff = globals::bfcooling_coeff[bflutindex]; - const double corrphotoioncoeff = !USE_LUT_PHOTOION ? -1 : globals::corrphotoioncoeff[bflutindex]; - const double bfheating_coeff = !USE_LUT_BFHEATING ? -1 : globals::bfheating_coeff[bflutindex]; - - fprintf(ratecoeff_file, "%la %la %la %la\n", alpha_sp, bfcooling_coeff, corrphotoioncoeff, bfheating_coeff); + fprintf(ratecoeff_file, "%la %la %la %la\n", spontrecombcoeffs[bflutindex], bfcooling_coeffs[bflutindex], + !USE_LUT_PHOTOION ? -1 : corrphotoioncoeffs[bflutindex], + !USE_LUT_BFHEATING ? -1 : globals::bfheating_coeff[bflutindex]); } } } @@ -258,9 +321,6 @@ static void write_ratecoeff_dat() { fclose(ratecoeff_file); } -///**************************************************************************** -/// The following functions define the integrands for these rate coefficients -/// for use with libgsl integrators. static auto alpha_sp_integrand_gsl(const double nu, void *const voidparas) -> double /// Integrand to calculate the rate coefficient for spontaneous recombination /// using gsl integrators. @@ -294,34 +354,10 @@ static auto alpha_sp_E_integrand_gsl(const double nu, void *const voidparas) -> return x; } -/*static double gamma_integrand_gsl(double nu, void *paras) -/// Integrand to calculate the rate coefficient for photoionization -/// using gsl integrators. -{ - double T = ((gslintegration_paras *) paras)->T; - double nu_edge = ((gslintegration_paras *) paras)->nu_edge; - - /// Information about the current level is passed via the global variable - /// mastate[tid] and its child values element, ion, level - /// MAKE SURE THAT THESE ARE SET IN THE CALLING FUNCTION!!!!!!!!!!!!!!!!! - double sigma_bf = photoionization_crosssection_fromtable(params->photoion_xs, nu_edge,nu); - - /// Dependence on dilution factor W is linear. This allows to set it here to - /// 1. and scale to its actual value later on. - double x = sigma_bf / H / nu * radfield::dbb(nu,T,1.); - //x = sigma_bf/H/nu * radfield::dbb(nu,T,1.); - //if (HOVERKB*nu/T < 1e-2) x = sigma_bf * pow(nu,2)/(HOVERKB*nu/T); - //else if (HOVERKB*nu/T >= 1e2) x = sigma_bf * pow(nu,2)*exp(-HOVERKB*nu/T); - //else x = sigma_bf * pow(nu,2)/(exp(HOVERKB*nu/T)-1); - - return x; -}*/ - static auto gammacorr_integrand_gsl(const double nu, void *const voidparas) -> double /// Integrand to calculate the rate coefficient for photoionization /// using gsl integrators. Corrected for stimulated recombination. { - assert_testmodeonly(USE_LUT_PHOTOION); const gslintegration_paras *const params = static_cast(voidparas); const float T = params->T; @@ -341,8 +377,6 @@ static auto approx_bfheating_integrand_gsl(const double nu, void *const voidpara /// formula. The radiation fields dependence on W is taken into account by multiplying /// the resulting expression with the correct W later on. { - assert_testmodeonly(USE_LUT_BFHEATING); - const gslintegration_paras *const params = static_cast(voidparas); const float T = params->T; @@ -366,30 +400,6 @@ static auto approx_bfheating_integrand_gsl(const double nu, void *const voidpara return x; } -/*double bfheating_integrand_gsl(double nu, void *paras) -/// Integrand to calculate the modified rate coefficient for photoionization -/// using gsl integrators. -{ - double get_groundlevelpop(int cellnumber, int element, int ion); - double x; - - int cellnumber = ((gslintegration_bfheatingparas *) paras)->cellnumber; - double nu_edge = ((gslintegration_bfheatingparas *) paras)->nu_edge; - - float T_e = globals::cell[cellnumber].T_e; - double T_R = globals::cell[cellnumber].T_R; - double W = globals::cell[cellnumber].W; - float nne = globals::cell[cellnumber].nne; - - double sigma_bf = photoionization_crosssection_fromtable(params->photoion_xs, nu_edge,nu); - double E_threshold = nu_edge*H; - double sfac = calculate_sahafact(element,ion,level,upperionlevel,T_e,E_threshold); - double nnionlevel = get_groundlevelpop(cellnumber,element,ion+1); - - x = sigma_bf*(1-nu_edge/nu)*radfield::dbb(nu,T_R,W) * (1-nnionlevel*nne/nnlevel*sf*exp(-H*nu/KB/T_e)); - return x; -}*/ - static auto bfcooling_integrand_gsl(const double nu, void *const voidparas) -> double /// Integrand to precalculate the bound-free heating ratecoefficient in an approximative way /// on a temperature grid using the assumption that T_e=T_R and W=1 in the ionisation @@ -511,7 +521,7 @@ static void precalculate_rate_coefficient_integrals() { double error = NAN; int status = 0; const float T_e = MINTEMP * exp(iter * T_step_log); - // T_e = MINTEMP + iter*T_step; + const double sfac = calculate_sahafact(element, ion, level, upperlevel, T_e, E_threshold); // printout("%d %g\n",iter,T_e); @@ -553,30 +563,7 @@ static void precalculate_rate_coefficient_integrals() { alpha_sp = 0; } // assert_always(alpha_sp >= 0); - globals::spontrecombcoeff[bflutindex] = alpha_sp; - - // if (atomic_number == 26 && ionstage == 3 && level < 5) - // { - // const double E_threshold_b = get_phixs_threshold(element, ion, level, phixstargetindex); - // const double sfac_b = calculate_sahafact(element,ion,level,upperlevel,T_e,E_threshold_b); - // const double nu_threshold_b = E_threshold_b / H; - // const double nu_max_phixs_b = nu_threshold * last_phixs_nuovernuedge; //nu of the uppermost point in - // the phixs table intparas.nu_edge = nu_threshold_b; // Global variable which passes the - // threshold to the integrator - // // the threshold of the first target gives nu of the - // first phixstable point - // double alpha_sp_new; - // status = gsl_integration_qag(&F_alpha_sp, nu_threshold_b, nu_max_phixs_b, 0, intaccuracy, GSLWSIZE, - // GSL_INTEG_GAUSS61, w, &alpha_sp_new, &error); alpha_sp_new *= FOURPI * sfac_b * phixstargetprobability; - // printout("recomb: T_e %6.1f Z=%d ionstage %d->%d upper+1 %5d lower+1 %5d sfac %7.2e sfac_new %7.2e - // alpha %7.2e alpha_new %7.2e threshold_ev %7.2e threshold_new_ev %7.2e\n", - // T_e, get_atomicnumber(element), get_ionstage(element, ion + 1), - // get_ionstage(element, ion), upperlevel + 1, level + 1, - // sfac, sfac_b, - // alpha_sp, alpha_sp_new, - // E_threshold / EV, - // E_threshold_b / EV); - // } + spontrecombcoeffs[bflutindex] = alpha_sp; // if (iter == 0) // printout("alpha_sp: element %d ion %d level %d upper level %d at temperature %g, alpha_sp is %g @@ -598,46 +585,46 @@ static void precalculate_rate_coefficient_integrals() { printout("WARNING: gammacorr was negative for level %d\n", level); gammacorr = 0; } - globals::corrphotoioncoeff[bflutindex] = gammacorr; + corrphotoioncoeffs[bflutindex] = gammacorr; } if constexpr (USE_LUT_BFHEATING) { - double bfheating_coeff = 0.0; + double this_bfheating_coeff = 0.0; const gsl_function F_bfheating = {.function = &approx_bfheating_integrand_gsl, .params = &intparas}; status = gsl_integration_qag(&F_bfheating, nu_threshold, nu_max_phixs, 0, RATECOEFF_INTEGRAL_ACCURACY, - GSLWSIZE, GSL_INTEG_GAUSS61, gslworkspace, &bfheating_coeff, &error); + GSLWSIZE, GSL_INTEG_GAUSS61, gslworkspace, &this_bfheating_coeff, &error); - if (status != 0 && (status != 18 || (error / bfheating_coeff) > epsrelwarning)) { + if (status != 0 && (status != 18 || (error / this_bfheating_coeff) > epsrelwarning)) { printout("bfheating_coeff integrator status %d. Integral value %9.3e +/- %9.3e\n", status, - bfheating_coeff, error); + this_bfheating_coeff, error); } - bfheating_coeff *= FOURPI * phixstargetprobability; - if (bfheating_coeff < 0) { + this_bfheating_coeff *= FOURPI * phixstargetprobability; + if (this_bfheating_coeff < 0) { printout("WARNING: bfheating_coeff was negative for level %d\n", level); - bfheating_coeff = 0; + this_bfheating_coeff = 0; } - globals::bfheating_coeff[bflutindex] = bfheating_coeff; + globals::bfheating_coeff[bflutindex] = this_bfheating_coeff; } - double bfcooling_coeff = 0.0; + double this_bfcooling_coeff = 0.0; const gsl_function F_bfcooling = {.function = &bfcooling_integrand_gsl, .params = &intparas}; status = gsl_integration_qag(&F_bfcooling, nu_threshold, nu_max_phixs, 0, RATECOEFF_INTEGRAL_ACCURACY, - GSLWSIZE, GSL_INTEG_GAUSS61, gslworkspace, &bfcooling_coeff, &error); - if (status != 0 && (status != 18 || (error / bfcooling_coeff) > epsrelwarning)) { + GSLWSIZE, GSL_INTEG_GAUSS61, gslworkspace, &this_bfcooling_coeff, &error); + if (status != 0 && (status != 18 || (error / this_bfcooling_coeff) > epsrelwarning)) { printout("bfcooling_coeff integrator status %d. Integral value %9.3e +/- %9.3e\n", status, - bfcooling_coeff, error); + this_bfcooling_coeff, error); } - bfcooling_coeff *= FOURPI * sfac * phixstargetprobability; - if (!std::isfinite(bfcooling_coeff) || bfcooling_coeff < 0) { + this_bfcooling_coeff *= FOURPI * sfac * phixstargetprobability; + if (!std::isfinite(this_bfcooling_coeff) || this_bfcooling_coeff < 0) { printout( "WARNING: bfcooling_coeff was negative or non-finite for level %d Te %g. bfcooling_coeff %g sfac %g " "phixstargetindex %d phixstargetprobability %g\n", - level, T_e, bfcooling_coeff, sfac, phixstargetindex, phixstargetprobability); - bfcooling_coeff = 0; + level, T_e, this_bfcooling_coeff, sfac, phixstargetindex, phixstargetprobability); + this_bfcooling_coeff = 0; } - globals::bfcooling_coeff[bflutindex] = bfcooling_coeff; + bfcooling_coeffs[bflutindex] = this_bfcooling_coeff; } } } @@ -663,11 +650,6 @@ auto select_continuum_nu(int element, int lowerion, int lower, int upperionlevel const double zrand = 1. - rng_uniform(); // Make sure that 0 < zrand <= 1 - // printout("emitted bf photon Z=%2d ionstage %d->%d upper %4d lower %4d lambda %7.1f lambda_edge %7.1f ratio %g zrand - // %g\n", - // get_atomicnumber(element), get_ionstage(element, lowerion + 1), get_ionstage(element, lowerion), upperionlevel, - // lower, 1e8 * CLIGHT / nu_selected, 1e8 * CLIGHT / nu_threshold, nu_selected / nu_threshold, zrand); - const double deltanu = (nu_max_phixs - nu_threshold) / npieces; double error = NAN; @@ -707,10 +689,6 @@ auto select_continuum_nu(int element, int lowerion, int lower, int upperionlevel auto get_spontrecombcoeff(int element, int ion, int level, int phixstargetindex, float T_e) -> double /// Returns the rate coefficient for spontaneous recombination. { - /*int lowerindex = floor((T-MINTEMP)/T_step); - int upperindex = lowerindex + 1; - double T_upper = MINTEMP + upperindex*T_step; - double T_lower = MINTEMP + lowerindex*T_step;*/ double Alpha_sp = NAN; const int lowerindex = floor(log(T_e / MINTEMP) / T_step_log); assert_always(lowerindex >= 0); @@ -719,13 +697,13 @@ auto get_spontrecombcoeff(int element, int ion, int level, int phixstargetindex, const double T_lower = MINTEMP * exp(lowerindex * T_step_log); const double T_upper = MINTEMP * exp(upperindex * T_step_log); - const double f_upper = globals::spontrecombcoeff[get_bflutindex(upperindex, element, ion, level, phixstargetindex)]; - const double f_lower = globals::spontrecombcoeff[get_bflutindex(lowerindex, element, ion, level, phixstargetindex)]; + const double f_upper = spontrecombcoeffs[get_bflutindex(upperindex, element, ion, level, phixstargetindex)]; + const double f_lower = spontrecombcoeffs[get_bflutindex(lowerindex, element, ion, level, phixstargetindex)]; // printout("interpolate_spontrecombcoeff element %d, ion %d, level %d, upper %g, lower %g\n", // element,ion,level,f_upper,f_lower); Alpha_sp = (f_lower + (f_upper - f_lower) / (T_upper - T_lower) * (T_e - T_lower)); } else { - Alpha_sp = globals::spontrecombcoeff[get_bflutindex(TABLESIZE - 1, element, ion, level, phixstargetindex)]; + Alpha_sp = spontrecombcoeffs[get_bflutindex(TABLESIZE - 1, element, ion, level, phixstargetindex)]; } return Alpha_sp; } @@ -844,17 +822,17 @@ static void scale_level_phixs(const int element, const int ion, const int level, const int nphixstargets = get_nphixstargets(element, ion, level); for (int phixstargetindex = 0; phixstargetindex < nphixstargets; phixstargetindex++) { for (int iter = 0; iter < TABLESIZE; iter++) { - globals::spontrecombcoeff[get_bflutindex(iter, element, ion, level, phixstargetindex)] *= factor; + spontrecombcoeffs[get_bflutindex(iter, element, ion, level, phixstargetindex)] *= factor; if constexpr (USE_LUT_PHOTOION) { - globals::corrphotoioncoeff[get_bflutindex(iter, element, ion, level, phixstargetindex)] *= factor; + corrphotoioncoeffs[get_bflutindex(iter, element, ion, level, phixstargetindex)] *= factor; } if constexpr (USE_LUT_BFHEATING) { globals::bfheating_coeff[get_bflutindex(iter, element, ion, level, phixstargetindex)] *= factor; } - globals::bfcooling_coeff[get_bflutindex(iter, element, ion, level, phixstargetindex)] *= factor; + bfcooling_coeffs[get_bflutindex(iter, element, ion, level, phixstargetindex)] *= factor; } } } @@ -1030,7 +1008,6 @@ void ratecoefficients_init() /// T_e = T_R for this precalculation. { /// Determine the temperture grids gridsize - T_step = (1. * MAXTEMP - MINTEMP) / (TABLESIZE - 1.); /// global variables T_step_log = (log(MAXTEMP) - log(MINTEMP)) / (TABLESIZE - 1.); md5_file("adata.txt", adatafile_hash); @@ -1087,14 +1064,12 @@ auto interpolate_corrphotoioncoeff(int element, int ion, int level, int phixstar const double T_lower = MINTEMP * exp(lowerindex * T_step_log); const double T_upper = MINTEMP * exp(upperindex * T_step_log); - const double f_upper = - globals::corrphotoioncoeff[get_bflutindex(upperindex, element, ion, level, phixstargetindex)]; - const double f_lower = - globals::corrphotoioncoeff[get_bflutindex(lowerindex, element, ion, level, phixstargetindex)]; + const double f_upper = corrphotoioncoeffs[get_bflutindex(upperindex, element, ion, level, phixstargetindex)]; + const double f_lower = corrphotoioncoeffs[get_bflutindex(lowerindex, element, ion, level, phixstargetindex)]; return (f_lower + (f_upper - f_lower) / (T_upper - T_lower) * (T - T_lower)); } - return globals::corrphotoioncoeff[get_bflutindex(TABLESIZE - 1, element, ion, level, phixstargetindex)]; + return corrphotoioncoeffs[get_bflutindex(TABLESIZE - 1, element, ion, level, phixstargetindex)]; } auto get_corrphotoioncoeff_ana(int element, int ion, int level, int phixstargetindex, int modelgridindex) -> double @@ -1210,6 +1185,21 @@ auto get_stimrecombcoeff(int element, int lowerion, int level, int phixstargetin return stimrecombcoeff; } +auto get_bfcoolingcoeff(int element, int ion, int level, int phixstargetindex, float T_e) -> double { + const int lowerindex = floor(log(T_e / MINTEMP) / T_step_log); + if (lowerindex < TABLESIZE - 1) { + const int upperindex = lowerindex + 1; + const double T_lower = MINTEMP * exp(lowerindex * T_step_log); + const double T_upper = MINTEMP * exp(upperindex * T_step_log); + + const double f_upper = bfcooling_coeffs[get_bflutindex(upperindex, element, ion, level, phixstargetindex)]; + const double f_lower = bfcooling_coeffs[get_bflutindex(lowerindex, element, ion, level, phixstargetindex)]; + + return (f_lower + (f_upper - f_lower) / (T_upper - T_lower) * (T_e - T_lower)); + } + return bfcooling_coeffs[get_bflutindex(TABLESIZE - 1, element, ion, level, phixstargetindex)]; +} + static auto integrand_corrphotoioncoeff_custom_radfield(const double nu, void *const voidparas) -> double /// Integrand to calculate the rate coefficient for photoionization /// using gsl integrators. Corrected for stimulated recombination. @@ -1229,7 +1219,6 @@ static auto integrand_corrphotoioncoeff_custom_radfield(const double nu, void *c const float sigma_bf = photoionization_crosssection_fromtable(params->photoion_xs, params->nu_edge, nu); - // const double Jnu = use_cellhist ? radfield::radfield(nu, modelgridindex) : radfield::dbb_mgi(nu, modelgridindex); const double Jnu = radfield::radfield(nu, modelgridindex); // TODO: MK thesis page 41, use population ratios and Te? @@ -1309,7 +1298,7 @@ auto get_corrphotoioncoeff(int element, int ion, int level, int phixstargetindex /// correction may be evaluated at T_R! double gammacorr = -1; - if (DETAILED_BF_ESTIMATORS_ON && globals::nts_global >= DETAILED_BF_ESTIMATORS_USEFROMTIMESTEP) { + if (DETAILED_BF_ESTIMATORS_ON && globals::timestep >= DETAILED_BF_ESTIMATORS_USEFROMTIMESTEP) { gammacorr = radfield::get_bfrate_estimator(element, ion, level, phixstargetindex, modelgridindex); // gammacorr will be -1 if no estimators available if (gammacorr > 0) { @@ -1338,8 +1327,8 @@ auto get_corrphotoioncoeff(int element, int ion, int level, int phixstargetindex const int index_in_groundlevelcontestimator = globals::elements[element].ions[ion].levels[level].closestgroundlevelcont; if (index_in_groundlevelcontestimator >= 0) { - gammacorr *= globals::corrphotoionrenorm[modelgridindex * get_nelements() * get_max_nions() + - index_in_groundlevelcontestimator]; + gammacorr *= + globals::corrphotoionrenorm[get_ionestimindex(modelgridindex, 0, 0) + index_in_groundlevelcontestimator]; } } } @@ -1365,7 +1354,7 @@ static auto get_nlevels_important(int modelgridindex, int element, int ion, bool return get_nlevels(element, ion); } // get the stored ion population for comparison with the cumulative sum of level pops - const double nnion_real = ionstagepop(modelgridindex, element, ion); + const double nnion_real = get_nnion(modelgridindex, element, ion); double nnlevelsum = 0.; int nlevels_important = get_ionisinglevels(element, ion); // levels needed to get majority of ion pop @@ -1399,6 +1388,43 @@ static auto get_nlevels_important(int modelgridindex, int element, int ion, bool return nlevels_important; } +auto iongamma_is_zero(const int modelgridindex, const int element, const int ion) -> bool { + const int nions = get_nions(element); + if (ion >= nions - 1) { + return true; + } + + if constexpr (USE_LUT_PHOTOION) { + return (globals::gammaestimator[get_ionestimindex(modelgridindex, element, ion)] == 0); + } + + const auto T_e = grid::get_Te(modelgridindex); + const auto nne = grid::get_nne(modelgridindex); + + for (int level = 0; level < get_nlevels(element, ion); level++) { + const double nnlevel = get_levelpop(modelgridindex, element, ion, level); + if (nnlevel == 0.) { + continue; + } + const int nphixstargets = get_nphixstargets(element, ion, level); + for (int phixstargetindex = 0; phixstargetindex < nphixstargets; phixstargetindex++) { + const int upperlevel = get_phixsupperlevel(element, ion, level, phixstargetindex); + + if (nnlevel * get_corrphotoioncoeff(element, ion, level, phixstargetindex, modelgridindex) > 0.) { + return false; + } + + const double epsilon_trans = epsilon(element, ion + 1, upperlevel) - epsilon(element, ion, level); + // printout("%g %g %g\n", get_levelpop(n,element,ion,level),col_ionization(n,0,epsilon_trans),epsilon_trans); + + if (nnlevel * col_ionization_ratecoeff(T_e, nne, element, ion, level, phixstargetindex, epsilon_trans) > 0) { + return false; + } + } + } + return true; +} + auto calculate_iongamma_per_gspop(const int modelgridindex, const int element, const int ion) -> double // ionisation rate coefficient. multiply by get_groundlevelpop to get a rate [s^-1] { diff --git a/ratecoeff.h b/ratecoeff.h index edf0a9688..aa2df0d3b 100644 --- a/ratecoeff.h +++ b/ratecoeff.h @@ -3,6 +3,8 @@ void ratecoefficients_init(); +void setup_photoion_luts(void); + double select_continuum_nu(int element, int lowerion, int lower, int upperionlevel, float T_e); double interpolate_corrphotoioncoeff(int element, int ion, int level, int phixstargetindex, double T); @@ -10,9 +12,13 @@ double interpolate_corrphotoioncoeff(int element, int ion, int level, int phixst double get_spontrecombcoeff(int element, int ion, int level, int phixstargetindex, float T_e); double get_stimrecombcoeff(int element, int lowerion, int level, int phixstargetindex, int modelgridindex); +double get_bfcoolingcoeff(int element, int ion, int level, int phixstargetindex, float T_e); + double get_corrphotoioncoeff(int element, int ion, int level, int phixstargetindex, int modelgridindex); double get_corrphotoioncoeff_ana(int element, int ion, int level, int phixstargetindex, int modelgridindex); +bool iongamma_is_zero(int modelgridindex, int element, int ion); + double calculate_iongamma_per_gspop(int modelgridindex, int element, int ion); double calculate_iongamma_per_ionpop(int modelgridindex, float T_e, int element, int lowerion, bool assume_lte, bool collisional_not_radiative, bool printdebug, bool force_bfest, diff --git a/rpkt.cc b/rpkt.cc index 3909a7faf..066980e99 100644 --- a/rpkt.cc +++ b/rpkt.cc @@ -3,9 +3,9 @@ #include #include #include +#include #include "atomic.h" -#include "boundary.h" #include "grid.h" #include "kpkt.h" #include "ltepop.h" @@ -22,44 +22,35 @@ constexpr int RPKT_EVENTTYPE_BB = 550; constexpr int RPKT_EVENTTYPE_CONT = 551; -constexpr auto operator<(const linelist_entry &line, const double &nu_cmf) -> bool { return !(line.nu <= nu_cmf); } - auto closest_transition(const double nu_cmf, const int next_trans) -> int /// for the propagation through non empty cells // find the next transition lineindex redder than nu_cmf // return -1 if no transition can be reached { - const int left = next_trans; - const int right = globals::nlines - 1; - - /// if nu_cmf is smaller than the lowest frequency in the linelist, - /// no line interaction is possible: return negative value as a flag - if (nu_cmf < globals::linelist[right].nu) { + if (next_trans > (globals::nlines - 1)) { + // packet is tagged as having no more line interactions return -1; } - if (left > right) { - // printout("[debug] pp should have no line interaction anymore\n"); + /// if nu_cmf is smaller than the lowest frequency in the linelist, + /// no line interaction is possible: return negative value as a flag + if (nu_cmf < globals::linelist[globals::nlines - 1].nu) { return -1; } - if (left > 0) { + if (next_trans > 0) { /// if left = pkt_ptr->next_trans > 0 we know the next line we should interact with, independent of the packets /// current nu_cmf which might be smaller than globals::linelist[left].nu due to propagation errors - return left; + return next_trans; } - if (nu_cmf >= globals::linelist[0].nu) { - /// if nu_cmf is larger than the highest frequency in the the linelist, - /// interaction with the first line occurs - no search - return 0; - } /// otherwise go through the list until nu_cmf is located between two - /// entries in the line list and get the index of the closest line - /// to lower frequencies - // will find the highest frequency (lowest index) line with nu_line <= nu_cmf // lower_bound matches the first element where the comparison function is false - const linelist_entry *matchline = - std::lower_bound(&globals::linelist[next_trans], &globals::linelist[globals::nlines], nu_cmf); - const int matchindex = matchline - globals::linelist; + const auto *matchline = + std::lower_bound(&globals::linelist[next_trans], &globals::linelist[globals::nlines], nu_cmf, + [](const auto &line, const double nu_cmf) -> bool { return line.nu > nu_cmf; }); + const int matchindex = std::distance(globals::linelist, matchline); + if (matchindex >= globals::nlines) { + return -1; + } return matchindex; } @@ -75,9 +66,6 @@ static auto get_event(const int modelgridindex, { // printout("get_event()\n"); /// initialize loop variables - double tau = 0.; /// initial optical depth along path - double dist = 0.; /// initial position on path - double edist = 0.; struct packet dummypkt_abort = *pkt_ptr; // this is done is two parts to get identical results to do_rpkt_step() @@ -90,83 +78,39 @@ static auto get_event(const int modelgridindex, const double d_nu_on_d_l = (nu_cmf_abort - pkt_ptr->nu_cmf) / abort_dist; struct packet dummypkt = *pkt_ptr; - struct packet *const dummypkt_ptr = &dummypkt; - calculate_kappa_rpkt_cont(pkt_ptr, &globals::kappa_rpkt_cont[tid]); - const double kap_cont = globals::kappa_rpkt_cont[tid].total * doppler_packet_nucmf_on_nurf(pkt_ptr); + calculate_chi_rpkt_cont(pkt_ptr->nu_cmf, &globals::chi_rpkt_cont[tid], modelgridindex, true); + const double chi_cont = + globals::chi_rpkt_cont[tid].total * doppler_packet_nucmf_on_nurf(pkt_ptr->pos, pkt_ptr->dir, pkt_ptr->prop_time); + double tau = 0.; // optical depth along path + double dist = 0.; // position on path while (true) { /// calculate distance to next line encounter ldist /// first select the closest transition in frequency /// we need its frequency nu_trans, the element/ion and the corresponding levels /// create therefore new variables in packet, which contain next_lowerlevel, ... - const int lineindex = closest_transition(dummypkt_ptr->nu_cmf, - dummypkt_ptr->next_trans); /// returns negative value if nu_cmf > nu_trans - + const int lineindex = closest_transition(dummypkt.nu_cmf, + dummypkt.next_trans); /// returns negative value if nu_cmf > nu_trans if (lineindex >= 0) { - /// line interaction in principle possible (nu_cmf > nu_trans) - // printout("[debug] get_event: line interaction possible\n"); + /// line interaction is possible (nu_cmf > nu_trans) const double nu_trans = globals::linelist[lineindex].nu; // helper variable to overcome numerical problems after line scattering // further scattering events should be located at lower frequencies to prevent - // multiple scattering events of one pp in a single line - dummypkt_ptr->next_trans = lineindex + 1; - - double ldist = NAN; // distance from current position to the line interaction - if (dummypkt_ptr->nu_cmf <= nu_trans) { - // printout( - // "[warning] packet %d dummypkt_ptr->nu_cmf %lg <= nu_trans %lg diff %lg next_trans %d, Z=%d ionstage %d - // " "lower %d upper %d\n", pkt_ptr->number, dummypkt_ptr->nu_cmf, nu_trans, (dummypkt_ptr->nu_cmf - - // nu_trans) / nu_trans, dummypkt_ptr->next_trans, get_atomicnumber(element), get_ionstage(element, ion), - // lower, upper); - ldist = 0; /// photon was propagated too far, make sure that we don't miss a line - } else if (!USE_RELATIVISTIC_DOPPLER_SHIFT) { - ldist = CLIGHT * dummypkt_ptr->prop_time * (dummypkt_ptr->nu_cmf / nu_trans - 1); - } else { - // With special relativity, the Doppler shift formula has an extra factor of 1/gamma in it, - // which changes the distance reach a line resonance and creates a dependence - // on packet position and direction - - // relativistic distance formula from tardis-sn project - // (committed by Christian Vogl, https://github.com/tardis-sn/tardis/pull/697) - // const double nu_r = nu_trans / dummypkt_ptr->nu_rf; - // const double ct = CLIGHT * dummypkt_ptr->prop_time; - // const double r = vec_len(dummypkt_ptr->pos); // radius - // const double mu = dot(dummypkt_ptr->dir, dummypkt_ptr->pos) / r; - // ldist = -mu * r + (ct - nu_r * nu_r * sqrt(ct * ct - (1 + r * r * (1 - mu * mu) * (1 + pow(nu_r, -2))))) / - // (1 + nu_r * nu_r); - - // use linear interpolation of frequency along the path - ldist = (nu_trans - dummypkt_ptr->nu_cmf) / (nu_cmf_abort - pkt_ptr->nu_cmf) * abort_dist; - } + // multiple scattering events of one packet in a single line + dummypkt.next_trans = lineindex + 1; - if (ldist < 0.) { - printout("[warning] ldist %lg < 0.\n", ldist); - assert_always(ldist >= -100.); - ldist = 0.; - } - - // printout("[debug] get_event: ldist %g\n",ldist); + const double ldist = get_linedistance(dummypkt.prop_time, dummypkt.nu_cmf, nu_trans, d_nu_on_d_l); - const double tau_cont = kap_cont * ldist; - - // printout("[debug] get_event: tau_rnd %g, tau %g, tau_cont %g\n", tau_rnd, tau, tau_cont); + const double tau_cont = chi_cont * ldist; if (tau_rnd - tau > tau_cont) { // got past the continuum optical depth so propagate to the line, and check interaction - // if ((dist + ldist) > abort_dist) { if (nu_trans < nu_cmf_abort) { - dummypkt_ptr->next_trans -= 1; // back up one line, because we didn't reach it before the boundary/timelimit - pkt_ptr->next_trans = dummypkt_ptr->next_trans; - - // const double nextline_nu = globals::linelist[pkt_ptr->next_trans].nu; - - // printout("[debug] get_event: leave propagation loop (dist %g > abort_dist %g) ... - // dummypkt_ptr->next_trans %d\n", dist, abort_dist, dummypkt_ptr->next_trans); - - // assert_always(nextline_nu <= nu_cmf_abort); + // back up one line, because we didn't reach it before the boundary/timelimit + pkt_ptr->next_trans = dummypkt.next_trans - 1; return std::numeric_limits::max(); } @@ -182,17 +126,7 @@ static auto get_event(const int modelgridindex, const double n_u = get_levelpop(modelgridindex, element, ion, upper); const double n_l = get_levelpop(modelgridindex, element, ion, lower); - double tau_line = (B_lu * n_l - B_ul * n_u) * HCLIGHTOVERFOURPI * dummypkt_ptr->prop_time; - - if (tau_line < 0) { - // printout("[warning] get_event: tau_line %g < 0, n_l %g, n_u %g, B_lu %g, B_ul %g, W %g, T_R %g, element - // %d, ion %d, upper %d, lower %d ... abort\n",tau_line, - // n_l,n_u,B_lu,B_ul,get_W(grid::get_cell_modelgridindex(pkt_ptr->where)),get_TR(grid::get_cell_modelgridindex(pkt_ptr->where)),element,ion,upper,lower); - // printout("[warning] get_event: set tau_line = 0\n"); - tau_line = 0.; - // printout("[fatal] get_event: tau_line < 0 ... abort\n"); - // abort(); - } + const double tau_line = std::max(0., (B_lu * n_l - B_ul * n_u) * HCLIGHTOVERFOURPI * dummypkt.prop_time); // printout("[debug] get_event: tau_line %g\n", tau_line); // printout("[debug] get_event: tau_rnd - tau > tau_cont\n"); @@ -203,54 +137,25 @@ static auto get_event(const int modelgridindex, // printout( // "[debug] get_event: tau_rnd - tau > tau_cont + tau_line ... proceed this packets " // "propagation\n"); - // printout("[debug] get_event: dist %g, abort_dist %g, dist-abort_dist %g\n", dist, abort_dist, - // dist - abort_dist); - - dist = dist + ldist; + dist += ldist; tau += tau_cont + tau_line; - if (!USE_RELATIVISTIC_DOPPLER_SHIFT) { - move_pkt_withtime(dummypkt_ptr, ldist); + + if constexpr (!USE_RELATIVISTIC_DOPPLER_SHIFT) { + move_pkt_withtime(&dummypkt, ldist); } else { // avoid move_pkt_withtime() to skip the standard Doppler shift calculation // and use the linear approx instead - dummypkt_ptr->pos[0] += (dummypkt_ptr->dir[0] * ldist); - dummypkt_ptr->pos[1] += (dummypkt_ptr->dir[1] * ldist); - dummypkt_ptr->pos[2] += (dummypkt_ptr->dir[2] * ldist); - dummypkt_ptr->prop_time += ldist / CLIGHT_PROP; - // dummypkt_ptr->nu_cmf = nu_trans; - dummypkt_ptr->nu_cmf = pkt_ptr->nu_cmf + d_nu_on_d_l * dist; - assert_testmodeonly(dummypkt_ptr->nu_cmf <= pkt_ptr->nu_cmf); + dummypkt.pos[0] += (dummypkt.dir[0] * ldist); + dummypkt.pos[1] += (dummypkt.dir[1] * ldist); + dummypkt.pos[2] += (dummypkt.dir[2] * ldist); + dummypkt.prop_time += ldist / CLIGHT_PROP; + dummypkt.nu_cmf = pkt_ptr->nu_cmf + d_nu_on_d_l * dist; // should equal nu_trans; + assert_testmodeonly(dummypkt.nu_cmf <= pkt_ptr->nu_cmf); } - // if (fabs(dummypkt_ptr->nu_cmf / nu_trans - 1.) > 1e-5) { - // printout("dopplercheck: packet %d nu_cmf %g nu_line %g ratio-1 %g errorfrac %g\n", pkt_ptr->number, - // dummypkt_ptr->nu_cmf, nu_trans, (dummypkt_ptr->nu_cmf - nu_trans) / nu_trans, - // fabs(dummypkt_ptr->nu_cmf / nu_trans - 1.)); - // } - radfield::update_lineestimator(modelgridindex, lineindex, - dummypkt_ptr->prop_time * CLIGHT * dummypkt_ptr->e_cmf / dummypkt_ptr->nu_cmf); - - // const int next_trans = dummypkt_ptr->next_trans; - // printout( - // "[debug] get_event: dummypkt_ptr->nu_cmf %g, nu(dummypkt_ptr->next_trans=%d) %g, " - // "nu(dummypkt_ptr->next_trans-1=%d) %g\n", - // dummypkt_ptr->nu_cmf, next_trans, globals::linelist[next_trans].nu, next_trans - 1, - // globals::linelist[next_trans - 1].nu); - // printout( - // "[debug] get_event: (dummypkt_ptr->nu_cmf - " - // "nu(dummypkt_ptr->next_trans-1))/dummypkt_ptr->nu_cmf %g\n", - // (dummypkt_ptr->nu_cmf - globals::linelist[next_trans - 1].nu) / dummypkt_ptr->nu_cmf); - - // if (dummypkt_ptr->nu_cmf >= globals::linelist[next_trans].nu && - // dummypkt_ptr->nu_cmf < globals::linelist[next_trans - 1].nu) { - // printout("[debug] get_event: nu(next_trans-1) > nu_cmf >= nu(next_trans)\n"); - // } else if (dummypkt_ptr->nu_cmf < globals::linelist[next_trans].nu) { - // printout("[debug] get_event: nu_cmf < nu(next_trans)\n"); - // } else { - // printout("[debug] get_event: nu_cmf >= nu(next_trans-1)\n"); - // } + dummypkt.prop_time * CLIGHT * dummypkt.e_cmf / dummypkt.nu_cmf); } else { /// bound-bound process occurs @@ -261,27 +166,10 @@ static auto get_event(const int modelgridindex, pkt_ptr->mastate.level = upper; /// if the MA will be activated it must be in the transitions upper level pkt_ptr->mastate.activatingline = lineindex; - edist = dist + ldist; - if (edist >= abort_dist) { - // if the edist > abort_dist, the line will not be activated in do_rpkt, even thought we are sure that we - // should hit based on the frequency checks - // this seems to only occur for kilonova models, maybe due to some combination of: - // - very rapid expansion - // - relativistic doppler shift (more complex expression causing numerical errors) - // - massive atomic dataset with densely packed lines - const double edist_new = abort_dist * (1 - 2e-8); - printout( - "[warning] bound-bound edist %lg was >= abort_dist %lg but nu_trans >= nu_cmf_abort (we haven't " - "redshifted past abort boundary). Fixing by reducing event distance to %lg ...\n", - edist, abort_dist, edist_new); - edist = edist_new; - } - - if (DETAILED_LINE_ESTIMATORS_ON) { - move_pkt_withtime(dummypkt_ptr, ldist); - radfield::update_lineestimator( - modelgridindex, lineindex, - dummypkt_ptr->prop_time * CLIGHT * dummypkt_ptr->e_cmf / dummypkt_ptr->nu_cmf); + if constexpr (DETAILED_LINE_ESTIMATORS_ON) { + move_pkt_withtime(&dummypkt, ldist); + radfield::update_lineestimator(modelgridindex, lineindex, + dummypkt.prop_time * CLIGHT * dummypkt.e_cmf / dummypkt.nu_cmf); } *rpkt_eventtype = RPKT_EVENTTYPE_BB; @@ -289,64 +177,46 @@ static auto get_event(const int modelgridindex, // printout("[debug] get_event: edist %g, abort_dist %g, edist-abort_dist %g, endloop // %d\n",edist,abort_dist,edist-abort_dist,endloop); - pkt_ptr->next_trans = dummypkt_ptr->next_trans; + pkt_ptr->next_trans = dummypkt.next_trans; - return edist; + return dist + ldist; } } else { - /// continuum process occurs - - edist = dist + (tau_rnd - tau) / kap_cont; - // assert_always((tau_rnd - tau) / kap_cont < ldist); - dummypkt_ptr->next_trans -= 1; - // printout("[debug] get_event: distance to the occuring continuum event %g, abort_dist %g\n", edist, - // abort_dist); + /// continuum process occurs before reaching the line *rpkt_eventtype = RPKT_EVENTTYPE_CONT; - pkt_ptr->next_trans = dummypkt_ptr->next_trans; + pkt_ptr->next_trans = dummypkt.next_trans - 1; - return edist; + return dist + (tau_rnd - tau) / chi_cont; } } else { /// no line interaction possible - check whether continuum process occurs in cell - // printout("[debug] get_event: line interaction impossible\n"); - - /// helper variable to overcome numerical problems after line scattering - dummypkt_ptr->next_trans = globals::nlines + 1; - - const double tau_cont = kap_cont * (abort_dist - dist); + const double tau_cont = chi_cont * (abort_dist - dist); if (tau_rnd - tau > tau_cont) { - /// travel out of cell or time step - // printout("[debug] get_event: travel out of cell or time step\n"); - - edist = std::numeric_limits::max(); - } else { - /// continuum process occurs at edist - edist = dist + (tau_rnd - tau) / kap_cont; - // printout("[debug] get_event: continuum process occurs at edist %g\n",edist); - - *rpkt_eventtype = RPKT_EVENTTYPE_CONT; + // no continuum event before abort_dist + return std::numeric_limits::max(); } + /// continuum process occurs at edist - pkt_ptr->next_trans = dummypkt_ptr->next_trans; + *rpkt_eventtype = RPKT_EVENTTYPE_CONT; - return edist; + pkt_ptr->next_trans = globals::nlines + 1; + + return dist + (tau_rnd - tau) / chi_cont; } } // should have already returned somewhere! assert_always(false); - - return edist; } static void electron_scatter_rpkt(struct packet *pkt_ptr) { /// now make the packet a r-pkt and set further flags pkt_ptr->type = TYPE_RPKT; - pkt_ptr->last_cross = NONE; /// allow all further cell crossings + pkt_ptr->last_cross = BOUNDARY_NONE; /// allow all further cell crossings double vel_vec[3]; get_velocity(pkt_ptr->pos, vel_vec, pkt_ptr->prop_time); @@ -426,10 +296,10 @@ static void electron_scatter_rpkt(struct packet *pkt_ptr) { double ref2[3]; meridian(old_dir_cmf, ref1, ref2); - /* This is the i1 angle of Bulla+2015, obtained by computing the angle between the - reference axes ref1 and ref2 in the meridian frame and the corresponding axes - ref1_sc and ref2_sc in the scattering plane. It is the supplementary angle of the - scatt angle phisc chosen in the rejection technique above (phisc+i1=180 or phisc+i1=540) */ + // This is the i1 angle of Bulla+2015, obtained by computing the angle between the + // reference axes ref1 and ref2 in the meridian frame and the corresponding axes + // ref1_sc and ref2_sc in the scattering plane. It is the supplementary angle of the + // scatt angle phisc chosen in the rejection technique above (phisc+i1=180 or phisc+i1=540) const double i1 = rot_angle(old_dir_cmf, new_dir_cmf, ref1, ref2); const double cos2i1 = cos(2 * i1); const double sin2i1 = sin(2 * i1); @@ -454,8 +324,8 @@ static void electron_scatter_rpkt(struct packet *pkt_ptr) { meridian(new_dir_cmf, ref1, ref2); // This is the i2 angle of Bulla+2015, obtained from the angle THETA between the - // reference axes ref1_sc and ref2_sc in the scattering plane and ref1 and ref2 in the - // meridian frame. NB: we need to add PI to transform THETA to i2 + // reference axes ref1_sc and ref2_sc in the scattering plane and ref1 and ref2 in the + // meridian frame. NB: we need to add PI to transform THETA to i2 const double i2 = PI + rot_angle(new_dir_cmf, old_dir_cmf, ref1, ref2); const double cos2i2 = cos(2 * i2); const double sin2i2 = sin(2 * i2); @@ -469,48 +339,48 @@ static void electron_scatter_rpkt(struct packet *pkt_ptr) { vel_rev[1] = -vel_vec[1]; vel_rev[2] = -vel_vec[2]; - double dummy_dir[3]; + double dummy_dir[3] = {NAN, NAN, NAN}; frame_transform(new_dir_cmf, &Q, &U, vel_rev, dummy_dir); pkt_ptr->stokes[0] = I; pkt_ptr->stokes[1] = Q; pkt_ptr->stokes[2] = U; - // ---------------------- Update rest frame direction, frequency and energy -------------------- + // Update rest frame direction, frequency and energy pkt_ptr->dir[0] = dummy_dir[0]; pkt_ptr->dir[1] = dummy_dir[1]; pkt_ptr->dir[2] = dummy_dir[2]; - // Check unit vector. + // Check unit vector assert_testmodeonly(fabs(vec_len(pkt_ptr->dir) - 1.) < 1.e-6); // Finally we want to put in the rest frame energy and frequency. // And record that it's now a r-pkt. - const double dopplerfactor = doppler_packet_nucmf_on_nurf(pkt_ptr); + const double dopplerfactor = doppler_packet_nucmf_on_nurf(pkt_ptr->pos, pkt_ptr->dir, pkt_ptr->prop_time); pkt_ptr->nu_rf = pkt_ptr->nu_cmf / dopplerfactor; pkt_ptr->e_rf = pkt_ptr->e_cmf / dopplerfactor; } -static void rpkt_event_continuum(struct packet *pkt_ptr, struct rpkt_cont_opacity kappa_rpkt_cont_thisthread, - int modelgridindex) { +static void rpkt_event_continuum(struct packet *pkt_ptr, + struct rpkt_continuum_absorptioncoeffs chi_rpkt_cont_thisthread, int modelgridindex) { const double nu = pkt_ptr->nu_cmf; - const double dopplerfactor = doppler_packet_nucmf_on_nurf(pkt_ptr); - const double kappa_cont = kappa_rpkt_cont_thisthread.total * dopplerfactor; - const double sigma = kappa_rpkt_cont_thisthread.es * dopplerfactor; - const double kappa_ff = kappa_rpkt_cont_thisthread.ff * dopplerfactor; - const double kappa_bf = kappa_rpkt_cont_thisthread.bf * dopplerfactor; + const double dopplerfactor = doppler_packet_nucmf_on_nurf(pkt_ptr->pos, pkt_ptr->dir, pkt_ptr->prop_time); + const double chi_cont = chi_rpkt_cont_thisthread.total * dopplerfactor; + const double sigma = chi_rpkt_cont_thisthread.es * dopplerfactor; + const double chi_ff = chi_rpkt_cont_thisthread.ff * dopplerfactor; + const double chi_bf = chi_rpkt_cont_thisthread.bf * dopplerfactor; - /// continuum process happens. select due to its probabilities sigma/kappa_cont, kappa_ff/kappa_cont, - /// kappa_bf/kappa_cont + /// continuum process happens. select due to its probabilities sigma/chi_cont, chi_ff/chi_cont, + /// chi_bf/chi_cont const double zrand = rng_uniform(); // printout("[debug] rpkt_event: r-pkt undergoes a continuum transition\n"); - // printout("[debug] rpkt_event: zrand*kappa_cont %g, sigma %g, kappa_ff %g, kappa_bf %g\n", zrand * kappa_cont, - // sigma, kappa_ff, kappa_bf); + // printout("[debug] rpkt_event: zrand*chi_cont %g, sigma %g, chi_ff %g, chi_bf %g\n", zrand * chi_cont, + // sigma, chi_ff, chi_bf); - if (zrand * kappa_cont < sigma) { + if (zrand * chi_cont < sigma) { /// electron scattering occurs /// in this case the packet stays a R_PKT of same nu_cmf than before (coherent scattering) /// but with different direction @@ -521,11 +391,7 @@ static void rpkt_event_continuum(struct packet *pkt_ptr, struct rpkt_cont_opacit stats::increment(stats::COUNTER_ESCOUNTER); // generate a virtual packet - if constexpr (VPKT_ON) { - int const realtype = 1; - pkt_ptr->last_cross = NONE; - vpkt_call_estimators(pkt_ptr, pkt_ptr->prop_time, realtype); - } + vpkt_call_estimators(pkt_ptr, TYPE_RPKT); // pkt_ptr->nu_cmf = 3.7474058e+14; electron_scatter_rpkt(pkt_ptr); @@ -538,7 +404,7 @@ static void rpkt_event_continuum(struct packet *pkt_ptr, struct rpkt_cont_opacit /// Set some flags // pkt_ptr->next_trans = 0; ///packet's comoving frame frequency is conserved during electron scattering /// don't touch the value of next_trans to save transition history - } else if (zrand * kappa_cont < sigma + kappa_ff) { + } else if (zrand * chi_cont < sigma + chi_ff) { /// ff: transform to k-pkt // printout("[debug] rpkt_event: free-free transition\n"); stats::increment(stats::COUNTER_K_STAT_FROM_FF); @@ -546,23 +412,23 @@ static void rpkt_event_continuum(struct packet *pkt_ptr, struct rpkt_cont_opacit pkt_ptr->last_event = 5; pkt_ptr->type = TYPE_KPKT; pkt_ptr->absorptiontype = -1; - } else if (zrand * kappa_cont < sigma + kappa_ff + kappa_bf) { + } else if (zrand * chi_cont < sigma + chi_ff + chi_bf) { /// bf: transform to k-pkt or activate macroatom corresponding to probabilities // printout("[debug] rpkt_event: bound-free transition\n"); pkt_ptr->absorptiontype = -2; - const double kappa_bf_inrest = kappa_rpkt_cont_thisthread.bf; - assert_always(globals::phixslist[tid].kappa_bf_sum[globals::nbfcontinua - 1] == kappa_bf_inrest); + const double chi_bf_inrest = chi_rpkt_cont_thisthread.bf; + assert_always(globals::phixslist[tid].chi_bf_sum[globals::nbfcontinua - 1] == chi_bf_inrest); /// Determine in which continuum the bf-absorption occurs const double zrand2 = rng_uniform(); - const double kappa_bf_rand = zrand2 * kappa_bf_inrest; + const double chi_bf_rand = zrand2 * chi_bf_inrest; - // first kappa_bf_sum[i] such that kappa_bf_sum[i] > kappa_bf_rand - double *upperval = std::upper_bound(&globals::phixslist[tid].kappa_bf_sum[0], - &globals::phixslist[tid].kappa_bf_sum[globals::nbfcontinua - 1], kappa_bf_rand); - const int allcontindex = std::distance(&globals::phixslist[tid].kappa_bf_sum[0], upperval); + // first chi_bf_sum[i] such that chi_bf_sum[i] > chi_bf_rand + double *upperval = std::upper_bound(&globals::phixslist[tid].chi_bf_sum[0], + &globals::phixslist[tid].chi_bf_sum[globals::nbfcontinua - 1], chi_bf_rand); + const int allcontindex = std::distance(&globals::phixslist[tid].chi_bf_sum[0], upperval); assert_always(allcontindex < globals::nbfcontinua); const double nu_edge = globals::allcont[allcontindex].nu_edge; @@ -661,7 +527,7 @@ static void rpkt_event_thickcell(struct packet *pkt_ptr) pkt_ptr->last_event = 12; stats::increment(stats::COUNTER_ESCOUNTER); - emitt_rpkt(pkt_ptr); + emit_rpkt(pkt_ptr); /// Electron scattering does not modify the last emission flag // pkt_ptr->emissiontype = get_continuumindex(element,ion-1,lower); /// but it updates the last emission position @@ -669,59 +535,12 @@ static void rpkt_event_thickcell(struct packet *pkt_ptr) pkt_ptr->em_time = pkt_ptr->prop_time; } -static void closest_transition_empty(struct packet *pkt_ptr) -/// for the propagation through empty cells -/// here its possible that the packet jumps over several lines -{ - // int left = 0; - int const left = pkt_ptr->next_trans; - // printout("[debug] closest_transition: initial left %d\n",left); - int const right = globals::nlines - 1; - - // printout("[debug] ___closest_transition___: initial left %d, right %d, nu_cmf %g\n",left,right,pkt_ptr->nu_cmf); - // printout("[debug] ___closest_transition___: nu_left %g, nu_right%g\n",linelist[left].nu,linelist[right].nu); - /// if nu_cmf is smaller than the lowest frequency in the linelist, - /// no line interaction is possible: return negative value as a flag - if (pkt_ptr->nu_cmf < globals::linelist[right].nu) { - pkt_ptr->next_trans = globals::nlines + 1; /// helper variable to overcome numerical problems after line scattering - } - if (left > right) { - // printout("[debug] pp should have no line interaction anymore\n"); - pkt_ptr->next_trans = globals::nlines + 1; /// helper variable to overcome numerical problems after line scattering - } - - int matchindex = 0; - /// no check for left > 0 in the empty case as it is possible that the packet is moved over - /// several lines through the empty cell - if (pkt_ptr->nu_cmf >= globals::linelist[left].nu) { - /// if nu_cmf is larger than the highest frequency in the allowed part of the linelist, - /// interaction with the first line of this part of the list occurs - matchindex = left; - } else { - /// otherwise go through the list until nu_cmf is located between two - /// entries in the line list and get the index of the closest line - /// to lower frequencies - - const linelist_entry *matchline = - std::lower_bound(&globals::linelist[pkt_ptr->next_trans], &globals::linelist[globals::nlines], pkt_ptr->nu_cmf); - matchindex = matchline - globals::linelist; - } - - /// For the empty case it's match not match+1: a line interaction is only possible in the next iteration - /// of the propagation loop. We just have to make sure that the next "normal" line search knows about the - /// current position of the photon in the frequency list. - pkt_ptr->next_trans = matchindex; /// helper variable to overcome numerical problems after line scattering - /// further scattering events should be located at lower frequencies to prevent - /// multiple scattering events of one pp in a single line -} - -static void update_estimators(struct packet *pkt_ptr, const double distance) +static void update_estimators(const struct packet *pkt_ptr, const double distance) /// Update the volume estimators J and nuJ /// This is done in another routine than move, as we sometimes move dummy /// packets which do not contribute to the radiation field. { - const int cellindex = pkt_ptr->where; - const int modelgridindex = grid::get_cell_modelgridindex(cellindex); + const int modelgridindex = grid::get_cell_modelgridindex(pkt_ptr->where); /// Update only non-empty cells if (modelgridindex == grid::get_npts_model()) { @@ -733,7 +552,7 @@ static void update_estimators(struct packet *pkt_ptr, const double distance) /// ffheatingestimator does not depend on ion and element, so an array with gridsize is enough. /// quick and dirty solution: store info in element=ion=0, and leave the others untouched (i.e. zero) - safeadd(globals::ffheatingestimator[modelgridindex], distance_e_cmf * globals::kappa_rpkt_cont[tid].ffheating); + safeadd(globals::ffheatingestimator[modelgridindex], distance_e_cmf * globals::chi_rpkt_cont[tid].ffheating); if constexpr (USE_LUT_PHOTOION || USE_LUT_BFHEATING) { const double distance_e_cmf_over_nu = distance_e_cmf / nu; @@ -745,7 +564,7 @@ static void update_estimators(struct packet *pkt_ptr, const double distance) if (nu > nu_edge) { const int element = globals::groundcont[i].element; /// Cells with zero abundance for a specific element have zero contribution - /// (set in calculate_kappa_rpkt_cont and therefore do not contribute to + /// (set in calculate_chi_rpkt_cont and therefore do not contribute to /// the estimators if (grid::get_elem_abundance(modelgridindex, element) > 0) { const int ion = globals::groundcont[i].ion; @@ -771,7 +590,7 @@ static void update_estimators(struct packet *pkt_ptr, const double distance) } } } else { - break; // because groundcont is sorted by nu_edge, nu < nu_edge for all remaining items + break; // because groundcont is sorted by nu_edge descending, nu < nu_edge for all remaining items } } } @@ -801,18 +620,19 @@ static auto do_rpkt_step(struct packet *pkt_ptr, const double t2) -> bool // boundaries. sdist is the boundary distance and snext is the // grid cell into which we pass. int snext = 0; - double sdist = boundary_cross(pkt_ptr, &snext); + double sdist = grid::boundary_distance(pkt_ptr->dir, pkt_ptr->pos, pkt_ptr->prop_time, pkt_ptr->where, &snext, + &pkt_ptr->last_cross); if (sdist == 0) { - change_cell(pkt_ptr, snext); + grid::change_cell(pkt_ptr, snext); const int cellindexnew = pkt_ptr->where; mgi = grid::get_cell_modelgridindex(cellindexnew); return (pkt_ptr->type == TYPE_RPKT && (mgi == grid::get_npts_model() || mgi == oldmgi)); } - const double maxsdist = (GRID_TYPE == GRID_SPHERICAL1D) - ? 2 * globals::rmax * (pkt_ptr->prop_time + sdist / CLIGHT_PROP) / globals::tmin - : globals::rmax * pkt_ptr->prop_time / globals::tmin; + const double maxsdist = (GRID_TYPE == GRID_CARTESIAN3D) + ? globals::rmax * pkt_ptr->prop_time / globals::tmin + : 2 * globals::rmax * (pkt_ptr->prop_time + sdist / CLIGHT_PROP) / globals::tmin; if (sdist > maxsdist) { printout("[fatal] do_rpkt: Unreasonably large sdist for packet %d. Rpkt. Abort. %g %g %g\n", pkt_ptr->number, globals::rmax, pkt_ptr->prop_time / globals::tmin, sdist); @@ -829,8 +649,8 @@ static auto do_rpkt_step(struct packet *pkt_ptr, const double t2) -> bool grid::get_cellcoordmin(cellindexnew, 0) * pkt_ptr->prop_time / globals::tmin, grid::get_cellcoordmin(cellindexnew, 1) * pkt_ptr->prop_time / globals::tmin, grid::get_cellcoordmin(cellindexnew, 2) * pkt_ptr->prop_time / globals::tmin); - printout("[warning] r_pkt: cell width %g\n", grid::wid_init(0) * pkt_ptr->prop_time / globals::tmin); - // abort(); + printout("[warning] r_pkt: cell width %g\n", grid::wid_init(cellindexnew, 0) * pkt_ptr->prop_time / globals::tmin); + assert_always(false); } if (((snext != -99) && (snext < 0)) || (snext >= grid::ngrid)) { printout("[fatal] r_pkt: Heading for inappropriate grid cell. Abort.\n"); @@ -848,71 +668,49 @@ static auto do_rpkt_step(struct packet *pkt_ptr, const double t2) -> bool // Find how far it can travel during the time inverval. - double const tdist = (t2 - pkt_ptr->prop_time) * CLIGHT_PROP; + const double tdist = (t2 - pkt_ptr->prop_time) * CLIGHT_PROP; assert_always(tdist >= 0); - double edist = NAN; + /// Get distance to the next physical event (continuum or bound-bound) + double edist = -1; int rpkt_eventtype = -1; - bool find_nextline = false; if (mgi == grid::get_npts_model()) { /// for empty cells no physical event occurs. The packets just propagate. edist = std::numeric_limits::max(); - find_nextline = true; - // printout("[debug] do_rpkt: propagating through empty cell, set edist=1e99\n"); + pkt_ptr->next_trans = -1; // skip over lines and search for line list position on the next non-empty cell } else if (grid::modelgrid[mgi].thick == 1) { /// In the case of optically thick cells, we treat the packets in grey approximation to speed up the calculation - /// Get distance to the next physical event in this case only electron scattering - // kappa = SIGMA_T*grid::get_nne(mgi); - const double kappa = grid::get_kappagrey(mgi) * grid::get_rho(mgi) * doppler_packet_nucmf_on_nurf(pkt_ptr); + + const double kappa = grid::get_kappagrey(mgi) * grid::get_rho(mgi) * + doppler_packet_nucmf_on_nurf(pkt_ptr->pos, pkt_ptr->dir, pkt_ptr->prop_time); const double tau_current = 0.0; edist = (tau_next - tau_current) / kappa; - find_nextline = true; - // printout("[debug] do_rpkt: propagating through grey cell, edist %g\n",edist); + pkt_ptr->next_trans = -1; } else { - // get distance to the next physical event (continuum or bound-bound) - edist = get_event(mgi, pkt_ptr, &rpkt_eventtype, tau_next, - fmin(tdist, sdist)); //, kappacont_ptr, sigma_ptr, kappaff_ptr, kappabf_ptr); - - // const int next_trans = pkt_ptr->next_trans; - // printout("[debug] do_rpkt: after edist: pkt_ptr->nu_cmf %g, nu(pkt_ptr->next_trans=%d) %g\n", pkt_ptr->nu_cmf, - // next_trans, globals::linelist[next_trans].nu); + edist = get_event(mgi, pkt_ptr, &rpkt_eventtype, tau_next, fmin(tdist, sdist)); } assert_always(edist >= 0); - // printout("[debug] do_rpkt: packet %d sdist, tdist, edist %g, %g, %g old_last_cross %d next_cross %d cellindex - // %d dir %g %g - // %g\n",pkt_ptr->number,sdist,tdist,edist,old_last_cross,pkt_ptr->last_cross,pkt_ptr->where,pkt_ptr->dir[0],pkt_ptr->dir[1],pkt_ptr->dir[2]); - if ((sdist < tdist) && (sdist < edist)) { - // printout("[debug] do_rpkt: sdist < tdist && sdist < edist\n"); // Move it into the new cell. move_pkt_withtime(pkt_ptr, sdist / 2.); update_estimators(pkt_ptr, sdist); move_pkt_withtime(pkt_ptr, sdist / 2.); if (snext != pkt_ptr->where) { - change_cell(pkt_ptr, snext); + grid::change_cell(pkt_ptr, snext); const int cellindexnew = pkt_ptr->where; mgi = grid::get_cell_modelgridindex(cellindexnew); } pkt_ptr->last_event = pkt_ptr->last_event + 100; - /// For empty or grey cells a photon can travel over several bb-lines. Thus we need to - /// find the next possible line interaction. - if (find_nextline) { - /// However, this is only required if the new cell is non-empty or non-grey - if (mgi != grid::get_npts_model() && grid::modelgrid[mgi].thick != 1) { - closest_transition_empty(pkt_ptr); - } - } - return (pkt_ptr->type == TYPE_RPKT && (mgi == grid::get_npts_model() || mgi == oldmgi)); } + if ((edist < sdist) && (edist < tdist)) { // bound-bound or continuum event - // printout("[debug] do_rpkt: edist < sdist && edist < tdist\n"); move_pkt_withtime(pkt_ptr, edist / 2.); update_estimators(pkt_ptr, edist); move_pkt_withtime(pkt_ptr, edist / 2.); @@ -923,30 +721,25 @@ static auto do_rpkt_step(struct packet *pkt_ptr, const double t2) -> bool } else if (rpkt_eventtype == RPKT_EVENTTYPE_BB) { rpkt_event_boundbound(pkt_ptr, mgi); } else if (rpkt_eventtype == RPKT_EVENTTYPE_CONT) { - rpkt_event_continuum(pkt_ptr, globals::kappa_rpkt_cont[tid], mgi); + rpkt_event_continuum(pkt_ptr, globals::chi_rpkt_cont[tid], mgi); } else { assert_always(false); } return (pkt_ptr->type == TYPE_RPKT && (mgi == grid::get_npts_model() || mgi == oldmgi)); } + if ((tdist < sdist) && (tdist < edist)) { // reaches end of timestep before cell boundary or interaction - // printout("[debug] do_rpkt: tdist < sdist && tdist < edist\n"); move_pkt_withtime(pkt_ptr, tdist / 2.); update_estimators(pkt_ptr, tdist); pkt_ptr->prop_time = t2; move_pkt(pkt_ptr, tdist / 2.); pkt_ptr->last_event = pkt_ptr->last_event + 1000; - /// For empty or grey cells a photon can travel over several bb-lines. Thus we need to - /// find the next possible line interaction. - if (find_nextline) { - closest_transition_empty(pkt_ptr); - } - return false; } + printout("[fatal] do_rpkt: Failed to identify event . Rpkt. edist %g, sdist %g, tdist %g Abort.\n", edist, sdist, tdist); printout("[fatal] do_rpkt: Trouble was due to packet number %d.\n", pkt_ptr->number); @@ -959,163 +752,10 @@ void do_rpkt(struct packet *pkt_ptr, const double t2) { } } -static auto get_rpkt_escapeprob_fromdirection(const double startpos[3], double start_nu_cmf, int startcellindex, - double tstart, double dirvec[3], enum cell_boundary last_cross, - double *tot_tau_cont, double *tot_tau_lines) -> double { - struct packet vpkt; - vpkt.type = TYPE_RPKT; - vpkt.nu_cmf = start_nu_cmf; - vpkt.where = startcellindex; - vpkt.next_trans = 0; - vpkt.last_cross = last_cross; - - vec_copy(vpkt.dir, dirvec); - vec_copy(vpkt.pos, startpos); - - vpkt.prop_time = tstart; - const double dopplerfactor = doppler_packet_nucmf_on_nurf(&vpkt); - vpkt.nu_rf = vpkt.nu_cmf / dopplerfactor; - - double t_future = tstart; - - int snext = -99; - bool end_packet = false; - while (!end_packet) { - const int cellindex = vpkt.where; - const int mgi = grid::get_cell_modelgridindex(cellindex); - if (grid::modelgrid[mgi].thick == 1) { - return 0.; - } - - // distance to the next cell - vpkt.prop_time = t_future; - const double sdist = boundary_cross(&vpkt, &snext); - - if (snext >= 0) { - const int nextmgi = grid::get_cell_modelgridindex(snext); - if (grid::modelgrid[nextmgi].thick == 1) { - return 0.; - } - } - - calculate_kappa_rpkt_cont(&vpkt, &globals::kappa_rpkt_cont[tid]); - - const double kappa_cont = globals::kappa_rpkt_cont[tid].total * doppler_packet_nucmf_on_nurf(&vpkt); - - *tot_tau_cont += kappa_cont * sdist; - - if ((*tot_tau_lines + *tot_tau_cont) > 10.) { - // printout("reached tau limit of %g\n", (tot_tau_lines + tot_tau_cont)); - return 0.; - } - - double ldist = 0.; - while (ldist < sdist) { - const int lineindex = closest_transition(vpkt.nu_cmf, vpkt.next_trans); - - if (lineindex >= 0) { - const double nutrans = globals::linelist[lineindex].nu; - - vpkt.next_trans = lineindex + 1; - - if (vpkt.nu_cmf < nutrans) { - ldist = 0; - } else { - ldist = CLIGHT * t_future * (vpkt.nu_cmf / nutrans - 1); - } - - assert_always(ldist >= 0.); - - if (ldist > sdist) { - // exit the while loop if you reach the boundary; go back to the previous transition to start next cell with - // the excluded line - - vpkt.next_trans -= 1; - break; - } - - const double t_line = t_future + ldist / CLIGHT; - const double tau_line = get_tau_sobolev(mgi, lineindex, t_line); - - *tot_tau_lines += tau_line; - } else { - vpkt.next_trans = globals::nlines + 1; - break; - } - } - - if (snext < 0 || grid::get_cell_modelgridindex(snext) == grid::get_npts_model()) { - break; - } - - t_future += (sdist / CLIGHT_PROP); - vpkt.prop_time = t_future; - move_pkt(&vpkt, sdist); - - if (snext != vpkt.where) { - vpkt.prop_time = t_future; - change_cell(&vpkt, snext); - end_packet = (vpkt.type == TYPE_ESCAPE); - } - } - - const double tau_escape = *tot_tau_cont + *tot_tau_lines; - const double escape_prob = exp(-tau_escape); - // printout(" tot_tau_lines %g tot_tau_cont %g escape_prob %g\n", - // tot_tau_lines, tot_tau_cont, escape_prob); - return escape_prob; -} - -auto get_rpkt_escape_prob(struct packet *pkt_ptr, const double tstart) -> double { - // return -1.; // disable this functionality and speed up the code - - const int startcellindex = pkt_ptr->where; - double startpos[3]; - vec_copy(startpos, pkt_ptr->pos); - const double start_nu_cmf = pkt_ptr->nu_cmf; - const enum cell_boundary last_cross = pkt_ptr->last_cross; - const int mgi = grid::get_cell_modelgridindex(startcellindex); - if (grid::modelgrid[mgi].thick == 1) { - // escape prob in thick cell is zero - return 0.; - } - const time_t sys_time_start_escape_prob = time(nullptr); - - const double pkt_radius = vec_len(startpos); - const double rmaxnow = globals::rmax * tstart / globals::tmin; - printout("get_rpkt_escape_prob pkt_radius %g rmax %g r/rmax %g tstart %g\n", pkt_radius, rmaxnow, - pkt_radius / rmaxnow, tstart); - // assert_always(pkt_radius <= rmaxnow); - double escape_prob_sum = 0.; - const int ndirs = 40; // number of random directions to sample - for (int n = 0; n < ndirs; n++) { - double dirvec[3]; - get_rand_isotropic_unitvec(dirvec); - double tau_cont = 0.; - double tau_lines = 0.; - const double escape_prob = get_rpkt_escapeprob_fromdirection(startpos, start_nu_cmf, startcellindex, tstart, dirvec, - last_cross, &tau_cont, &tau_lines); - escape_prob_sum += escape_prob; - - printout( - "randomdir no. %d (dir dot pos) %g dir %g %g %g tau_lines %g tau_cont %g escape_prob %g escape_prob_avg %g\n", - n, dot(startpos, dirvec), dirvec[0], dirvec[1], dirvec[2], tau_cont, tau_lines, escape_prob, - escape_prob_sum / (n + 1)); - } - const double escape_prob_avg = escape_prob_sum / ndirs; - printout("from %d random directions, average escape probability is %g (took %ld s)\n", ndirs, escape_prob_avg, - time(nullptr) - sys_time_start_escape_prob); - - // reset the cell history and rpkt opacities back to values for the start point - cellhistory_reset(mgi, false); - - return escape_prob_avg; -} - -void emitt_rpkt(struct packet *pkt_ptr) { +void emit_rpkt(struct packet *pkt_ptr) { /// now make the packet a r-pkt and set further flags pkt_ptr->type = TYPE_RPKT; - pkt_ptr->last_cross = NONE; /// allow all further cell crossings + pkt_ptr->last_cross = BOUNDARY_NONE; /// allow all further cell crossings /// Need to assign a new direction. Assume isotropic emission in the cmf @@ -1135,7 +775,7 @@ void emitt_rpkt(struct packet *pkt_ptr) { /// Finally we want to put in the rest frame energy and frequency. And record /// that it's now a r-pkt. - const double dopplerfactor = doppler_packet_nucmf_on_nurf(pkt_ptr); + const double dopplerfactor = doppler_packet_nucmf_on_nurf(pkt_ptr->pos, pkt_ptr->dir, pkt_ptr->prop_time); pkt_ptr->nu_rf = pkt_ptr->nu_cmf / dopplerfactor; pkt_ptr->e_rf = pkt_ptr->e_cmf / dopplerfactor; @@ -1144,14 +784,11 @@ void emitt_rpkt(struct packet *pkt_ptr) { pkt_ptr->stokes[1] = 0.; pkt_ptr->stokes[2] = 0.; - double dummy_dir[3]; - dummy_dir[0] = dummy_dir[1] = 0.0; - dummy_dir[2] = 1.0; + std::array dummy_dir = {0., 0., 1.}; cross_prod(pkt_ptr->dir, dummy_dir, pkt_ptr->pol_dir); if ((dot(pkt_ptr->pol_dir, pkt_ptr->pol_dir)) < 1.e-8) { - dummy_dir[0] = dummy_dir[2] = 0.0; - dummy_dir[1] = 1.0; + dummy_dir = {0., 0., 1.}; cross_prod(pkt_ptr->dir, dummy_dir, pkt_ptr->pol_dir); } @@ -1161,67 +798,50 @@ void emitt_rpkt(struct packet *pkt_ptr) { // printout("pkt direction %g, %g, %g\n",pkt_ptr->dir[0],pkt_ptr->dir[1],pkt_ptr->dir[2]); } -static auto calculate_kappa_ff(const int modelgridindex, const double nu) -> double -/// free-free opacity +static auto calculate_chi_ff(const int modelgridindex, const double nu) -> double +// calculate the free-free absorption coefficient [cm^-1] +// = kappa(free-free) * nne { assert_always(nu > 0.); const double g_ff = 1; - const float nne = grid::get_nne(modelgridindex); + const auto nne = grid::get_nne(modelgridindex); const auto T_e = grid::get_Te(modelgridindex); - double kappa_ff = 0.; - // kappa_ffheating = 0.; + double chi_ff = 0.; + // chi_ffheating = 0.; const int nelements = get_nelements(); for (int element = 0; element < nelements; element++) { for (int ion = 0; ion < get_nions(element); ion++) { - /// calculate population of ionstage ... - const double nnion = ionstagepop(modelgridindex, element, ion); - // Z = get_atomicnumber(element); ///atomic number - // if (get_ionstage(element,ion) > 1) - /// Z is ionic charge in the following formula - const int Z = get_ionstage(element, ion) - 1; - if (Z > 0) { - // kappa_ff += 3.69255e8 * pow(Z,2) / sqrt(T_e) * pow(nu,-3) * g_ff * nne * nnion * (1-exp(-HOVERKB*nu/T_e)); - kappa_ff += Z * Z * g_ff * nnion; - // kappa_ffheating += pow(Z,2) * g_ff * nnion; - /// heating with level dependence - // kappa_ffheating += 3.69255e8 * pow(Z,2) / sqrt(T_e) * pow(nu,-3) * g_ff * nne * nnion * (1 - - // exp(-HOVERKB*nu/T_e)); - /// heating without level dependence - // kappa_ffheating += 3.69255e8 * pow(Z,2) * pow(nu,-3) * g_ff * (1-exp(-HOVERKB*nu/T_e)); - // if (!std::isfinite(kappa_ff)) { - // printout("kappa_ff %g nne %g T_e %g mgi %d element %d ion %d nnion %g\n", kappa_ff, nne, T_e, - // modelgridindex, - // element, ion, nnion); - // } - } + const double nnion = get_nnion(modelgridindex, element, ion); + const int ioncharge = get_ionstage(element, ion) - 1; + chi_ff += ioncharge * ioncharge * g_ff * nnion; } } - kappa_ff *= 3.69255e8 / sqrt(T_e) * pow(nu, -3) * nne * (1 - exp(-HOVERKB * nu / T_e)); + chi_ff *= 3.69255e8 / sqrt(T_e) * pow(nu, -3) * nne * (1 - exp(-HOVERKB * nu / T_e)); - if (!std::isfinite(kappa_ff)) { - printout("ERRORL: kappa_ff is non-infinite mgi %d nne %g nu %g T_e %g\n", modelgridindex, nne, nu, T_e); + if (!std::isfinite(chi_ff)) { + printout("ERRORL: chi_ff is non-infinite mgi %d nne %g nu %g T_e %g\n", modelgridindex, nne, nu, T_e); abort(); } - // kappa_ffheating *= 3.69255e8 / sqrt(T_e) * pow(nu,-3) * nne * (1 - exp(-HOVERKB*nu/T_e)); - // kappa_ff *= 1e5; - return kappa_ff; + + return chi_ff; } -auto calculate_kappa_bf_gammacontr(const int modelgridindex, const double nu) -> double +template +auto calculate_chi_bf_gammacontr(const int modelgridindex, const double nu) -> double // bound-free opacity { - double kappa_bf_sum = 0.; - if constexpr (USE_LUT_PHOTOION || USE_LUT_BFHEATING) { + double chi_bf_sum = 0.; + if constexpr (usecellhistupdatephixslist && (USE_LUT_PHOTOION || USE_LUT_BFHEATING)) { for (int gphixsindex = 0; gphixsindex < globals::nbfcontinua_ground; gphixsindex++) { globals::phixslist[tid].groundcont_gamma_contr[gphixsindex] = 0.; } } - const double T_e = grid::get_Te(modelgridindex); - const double nne = grid::get_nne(modelgridindex); - const double nnetot = grid::get_nnetot(modelgridindex); + const auto T_e = grid::get_Te(modelgridindex); + const auto nne = grid::get_nne(modelgridindex); + const auto nnetot = grid::get_nnetot(modelgridindex); /// The phixslist is sorted by nu_edge in ascending order (longest to shortest wavelength) /// If nu < allcont[i].nu_edge no absorption in any of the following continua @@ -1243,67 +863,56 @@ auto calculate_kappa_bf_gammacontr(const int modelgridindex, const double nu) -> /// the involved atomic species if ((DETAILED_BF_ESTIMATORS_ON && grid::get_elem_abundance(modelgridindex, element) > 0) || - (!DETAILED_BF_ESTIMATORS_ON && - ((ionstagepop(modelgridindex, element, ion) / nnetot > 1.e-6) || (level == 0)))) { + (!DETAILED_BF_ESTIMATORS_ON && ((get_nnion(modelgridindex, element, ion) / nnetot > 1.e-6) || (level == 0)))) { const double nu_edge = globals::allcont[i].nu_edge; - // const int phixstargetindex = globals::allcont[i].phixstargetindex; - const double nnlevel = get_levelpop(modelgridindex, element, ion, level); - // printout("i %d, nu_edge %g\n",i,nu_edge); - const double nu_max_phixs = nu_edge * last_phixs_nuovernuedge; // nu of the uppermost point in the phixs table if (nu < nu_edge) { break; } + const double nnlevel = usecellhistupdatephixslist ? get_levelpop(modelgridindex, element, ion, level) + : calculate_levelpop(modelgridindex, element, ion, level); + const double nu_max_phixs = nu_edge * last_phixs_nuovernuedge; // nu of the uppermost point in the phixs table if (nu <= nu_max_phixs && nnlevel > 0) { - // printout("element %d, ion %d, level %d, nnlevel %g\n",element,ion,level,nnlevel); - // const double sigma_bf = photoionization_crosssection(element, ion, level, nu_edge, nu); - // const double sigma_bf = photoionization_crosssection_fromtable( - // globals::elements[element].ions[ion].levels[level].photoion_xs, nu_edge, nu); const double sigma_bf = photoionization_crosssection_fromtable(globals::allcont[i].photoion_xs, nu_edge, nu); - // const double probability = get_phixsprobability(element, ion, level, phixstargetindex); const double probability = globals::allcont[i].probability; - // assert_always(probability == probability2); - double corrfactor = NAN; - if constexpr (SEPARATE_STIMRECOMB) { - corrfactor = 1.; // no subtraction of stimulated recombination - } else { + double corrfactor = 1.; // default to no subtraction of stimulated recombination + if constexpr (!SEPARATE_STIMRECOMB) { double departure_ratio = globals::cellhistory[tid].ch_allcont_departureratios[i]; - if (departure_ratio < 0) { - // const int upper = get_phixsupperlevel(element, ion, level, phixstargetindex); - + if (!usecellhistupdatephixslist || departure_ratio < 0) { const int upper = globals::allcont[i].upperlevel; - const double nnupperionlevel = get_levelpop(modelgridindex, element, ion + 1, upper); + const double nnupperionlevel = usecellhistupdatephixslist + ? get_levelpop(modelgridindex, element, ion + 1, upper) + : calculate_levelpop(modelgridindex, element, ion + 1, upper); const double sf = calculate_sahafact(element, ion, level, upper, T_e, H * nu_edge); departure_ratio = nnupperionlevel / nnlevel * nne * sf; // put that to phixslist - globals::cellhistory[tid].ch_allcont_departureratios[i] = departure_ratio; + if (usecellhistupdatephixslist) { + globals::cellhistory[tid].ch_allcont_departureratios[i] = departure_ratio; + } } const double stimfactor = departure_ratio * exp(-HOVERKB * nu / T_e); - corrfactor = 1 - stimfactor; // photoionisation minus stimulated recombination - if (corrfactor < 0) { - corrfactor = 0.; - } - // const double corrfactor = 1.; // no subtraction of stimulated recombination + corrfactor = std::max(0., 1 - stimfactor); // photoionisation minus stimulated recombination } - const double kappa_bf_contr = nnlevel * sigma_bf * probability * corrfactor; + const double sigma_contr = sigma_bf * probability * corrfactor; - if constexpr (USE_LUT_PHOTOION || USE_LUT_BFHEATING) { + if constexpr (usecellhistupdatephixslist && (USE_LUT_PHOTOION || USE_LUT_BFHEATING)) { if (level == 0) { const int gphixsindex = globals::allcont[i].index_in_groundphixslist; - globals::phixslist[tid].groundcont_gamma_contr[gphixsindex] += sigma_bf * probability * corrfactor; + globals::phixslist[tid].groundcont_gamma_contr[gphixsindex] += sigma_contr; } } - if constexpr (DETAILED_BF_ESTIMATORS_ON) { - globals::phixslist[tid].gamma_contr[i] = sigma_bf * probability * corrfactor; + if constexpr (usecellhistupdatephixslist && DETAILED_BF_ESTIMATORS_ON) { + globals::phixslist[tid].gamma_contr[i] = sigma_contr; } - if (!std::isfinite(kappa_bf_contr)) { - printout("[fatal] calculate_kappa_rpkt_cont: non-finite contribution to kappa_bf_contr %g ... abort\n", - kappa_bf_contr); + const double chi_bf_contr = nnlevel * sigma_contr; + if (usecellhistupdatephixslist && !std::isfinite(chi_bf_contr)) { + printout("[fatal] calculate_chi_rpkt_cont: non-finite contribution to chi_bf_contr %g ... abort\n", + chi_bf_contr); printout("[fatal] phixslist index %d, element %d, ion %d, level %d\n", i, element, ion, level); printout("[fatal] Z=%d ionstage %d\n", get_atomicnumber(element), get_ionstage(element, ion)); printout("[fatal] globals::cell[%d].composition[%d].abundance = %g\n", modelgridindex, element, @@ -1315,53 +924,54 @@ auto calculate_kappa_bf_gammacontr(const int modelgridindex, const double nu) -> abort(); } - kappa_bf_sum += kappa_bf_contr; - globals::phixslist[tid].kappa_bf_sum[i] = kappa_bf_sum; - } else { + chi_bf_sum += chi_bf_contr; + if constexpr (usecellhistupdatephixslist) { + globals::phixslist[tid].chi_bf_sum[i] = chi_bf_sum; + } + } else if constexpr (usecellhistupdatephixslist) { // ignore this particular process - globals::phixslist[tid].kappa_bf_sum[i] = kappa_bf_sum; + globals::phixslist[tid].chi_bf_sum[i] = chi_bf_sum; if constexpr (DETAILED_BF_ESTIMATORS_ON) { globals::phixslist[tid].gamma_contr[i] = 0.; } } - } else // no element present or not an important level - { - globals::phixslist[tid].kappa_bf_sum[i] = kappa_bf_sum; + } else if constexpr (usecellhistupdatephixslist) { + // no element present or not an important level + globals::phixslist[tid].chi_bf_sum[i] = chi_bf_sum; if constexpr (DETAILED_BF_ESTIMATORS_ON) { globals::phixslist[tid].gamma_contr[i] = 0.; } } } - for (; i < globals::nbfcontinua; i++) { - globals::phixslist[tid].kappa_bf_sum[i] = kappa_bf_sum; - if constexpr (DETAILED_BF_ESTIMATORS_ON) { - globals::phixslist[tid].gamma_contr[i] = 0.; + if constexpr (usecellhistupdatephixslist) { + for (; i < globals::nbfcontinua; i++) { + globals::phixslist[tid].chi_bf_sum[i] = chi_bf_sum; + if constexpr (DETAILED_BF_ESTIMATORS_ON) { + globals::phixslist[tid].gamma_contr[i] = 0.; + } } } - return kappa_bf_sum; + + return chi_bf_sum; } -void calculate_kappa_rpkt_cont(const struct packet *const pkt_ptr, - struct rpkt_cont_opacity *kappa_rpkt_cont_thisthread) { - const int cellindex = pkt_ptr->where; - const int modelgridindex = grid::get_cell_modelgridindex(cellindex); - assert_always(modelgridindex != grid::get_npts_model()); - assert_always(grid::modelgrid[modelgridindex].thick != 1); - const double nu_cmf = pkt_ptr->nu_cmf; - if ((modelgridindex == kappa_rpkt_cont_thisthread->modelgridindex) && - (!kappa_rpkt_cont_thisthread->recalculate_required) && - (fabs(kappa_rpkt_cont_thisthread->nu / nu_cmf - 1.0) < 1e-4)) { +void calculate_chi_rpkt_cont(const double nu_cmf, struct rpkt_continuum_absorptioncoeffs *chi_rpkt_cont_thisthread, + const int modelgridindex, const bool usecellhistupdatephixslist) { + assert_testmodeonly(modelgridindex != grid::get_npts_model()); + assert_testmodeonly(grid::modelgrid[modelgridindex].thick != 1); + if ((modelgridindex == chi_rpkt_cont_thisthread->modelgridindex) && + (!chi_rpkt_cont_thisthread->recalculate_required) && (fabs(chi_rpkt_cont_thisthread->nu / nu_cmf - 1.0) < 1e-4)) { // calculated values are a match already return; } - const float nne = grid::get_nne(modelgridindex); + const auto nne = grid::get_nne(modelgridindex); double sigma = 0.0; - double kappa_ff = 0.; - double kappa_bf = 0.; - double kappa_ffheating = 0.; + double chi_ff = 0.; + double chi_bf = 0.; + double chi_ffheating = 0.; if (globals::opacity_case == 4) { /// First contribution: Thomson scattering on free electrons @@ -1373,55 +983,56 @@ void calculate_kappa_rpkt_cont(const struct packet *const pkt_ptr, // sigma *= 0.1; /// Second contribution: free-free absorption - kappa_ff = calculate_kappa_ff(modelgridindex, nu_cmf); - kappa_ffheating = kappa_ff; + chi_ff = calculate_chi_ff(modelgridindex, nu_cmf); + chi_ffheating = chi_ff; /// Third contribution: bound-free absorption - kappa_bf = calculate_kappa_bf_gammacontr(modelgridindex, nu_cmf); + chi_bf = usecellhistupdatephixslist ? calculate_chi_bf_gammacontr(modelgridindex, nu_cmf) + : calculate_chi_bf_gammacontr(modelgridindex, nu_cmf); // const double pkt_lambda = 1e8 * CLIGHT / nu_cmf; // if (pkt_lambda < 4000) // { - // printout("lambda %7.1f kappa_bf %g \n", pkt_lambda, kappa_bf); + // printout("lambda %7.1f chi_bf %g \n", pkt_lambda, chi_bf); // } } else { - /// in the other cases kappa_grey is an mass absorption coefficient + /// in the other cases chi_grey is an mass absorption coefficient /// therefore use the mass density - // sigma = globals::cell[pkt_ptr->where].kappa_grey * globals::cell[pkt_ptr->where].rho; + // sigma = globals::cell[pkt_ptr->where].chi_grey * globals::cell[pkt_ptr->where].rho; // sigma = SIGMA_T * nne; sigma = 0.; - // kappa_ff = 0.9*sigma; + // chi_ff = 0.9*sigma; // sigma *= 0.1; - // kappa_bf = 0.; + // chi_bf = 0.; // Second contribution: free-free absorption - kappa_ff = 1e5 * calculate_kappa_ff(modelgridindex, nu_cmf); + chi_ff = 1e5 * calculate_chi_ff(modelgridindex, nu_cmf); - kappa_bf = 0.; + chi_bf = 0.; } - kappa_rpkt_cont_thisthread->nu = nu_cmf; - kappa_rpkt_cont_thisthread->modelgridindex = modelgridindex; - kappa_rpkt_cont_thisthread->recalculate_required = false; - kappa_rpkt_cont_thisthread->total = sigma + kappa_bf + kappa_ff; - kappa_rpkt_cont_thisthread->es = sigma; - kappa_rpkt_cont_thisthread->ff = kappa_ff; - kappa_rpkt_cont_thisthread->bf = kappa_bf; - kappa_rpkt_cont_thisthread->ffheating = kappa_ffheating; - // kappa_rpkt_cont_thisthread.bfheating = kappa_bfheating; - - if (!std::isfinite(kappa_rpkt_cont_thisthread->total)) { - printout("[fatal] calculate_kappa_rpkt_cont: resulted in non-finite kappa_rpkt_cont.total ... abort\n"); - printout("[fatal] es %g, ff %g, bf %g\n", kappa_rpkt_cont_thisthread->es, kappa_rpkt_cont_thisthread->ff, - kappa_rpkt_cont_thisthread->bf); + chi_rpkt_cont_thisthread->nu = nu_cmf; + chi_rpkt_cont_thisthread->modelgridindex = modelgridindex; + chi_rpkt_cont_thisthread->recalculate_required = false; + chi_rpkt_cont_thisthread->total = sigma + chi_bf + chi_ff; + chi_rpkt_cont_thisthread->es = sigma; + chi_rpkt_cont_thisthread->ff = chi_ff; + chi_rpkt_cont_thisthread->bf = chi_bf; + chi_rpkt_cont_thisthread->ffheating = chi_ffheating; + // chi_rpkt_cont_thisthread.bfheating = chi_bfheating; + + if (!std::isfinite(chi_rpkt_cont_thisthread->total)) { + printout("[fatal] calculate_chi_rpkt_cont: resulted in non-finite chi_rpkt_cont.total ... abort\n"); + printout("[fatal] es %g, ff %g, bf %g\n", chi_rpkt_cont_thisthread->es, chi_rpkt_cont_thisthread->ff, + chi_rpkt_cont_thisthread->bf); printout("[fatal] nbfcontinua %d\n", globals::nbfcontinua); printout("[fatal] in cell %d with density %g\n", modelgridindex, grid::get_rho(modelgridindex)); - printout("[fatal] pkt_ptr->nu_cmf %g\n", pkt_ptr->nu_cmf); - if (std::isfinite(kappa_rpkt_cont_thisthread->es)) { - kappa_rpkt_cont_thisthread->ff = 0.; - kappa_rpkt_cont_thisthread->bf = 0.; - kappa_rpkt_cont_thisthread->total = kappa_rpkt_cont_thisthread->es; + printout("[fatal] pkt_ptr->nu_cmf %g\n", nu_cmf); + if (std::isfinite(chi_rpkt_cont_thisthread->es)) { + chi_rpkt_cont_thisthread->ff = 0.; + chi_rpkt_cont_thisthread->bf = 0.; + chi_rpkt_cont_thisthread->total = chi_rpkt_cont_thisthread->es; } else { abort(); } diff --git a/rpkt.h b/rpkt.h index 2c621dbad..6b4db7593 100644 --- a/rpkt.h +++ b/rpkt.h @@ -1,11 +1,33 @@ #ifndef RPKT_H #define RPKT_H +#include "artisoptions.h" +#include "constants.h" + void do_rpkt(struct packet *pkt_ptr, double t2); -void emitt_rpkt(struct packet *pkt_ptr); +void emit_rpkt(struct packet *pkt_ptr); int closest_transition(double nu_cmf, int next_trans); -double get_rpkt_escape_prob(struct packet *pkt_ptr, double tstart); -double calculate_kappa_bf_gammacontr(int modelgridindex, double nu); -void calculate_kappa_rpkt_cont(const struct packet *pkt_ptr, struct rpkt_cont_opacity *kappa_rpkt_cont_thisthread); +double calculate_chi_bf_gammacontr(int modelgridindex, double nu); +void calculate_chi_rpkt_cont(double nu_cmf, struct rpkt_continuum_absorptioncoeffs *chi_rpkt_cont_thisthread, + int modelgridindex, bool usecellhistupdatephixslist); + +constexpr auto get_linedistance(const double prop_time, const double nu_cmf, const double nu_trans, + const double d_nu_on_d_l) -> double { + // distance from packet position to redshifting into line at frequency nu_trans + + if (nu_cmf <= nu_trans) { + return 0; /// photon was propagated too far, make sure that we don't miss a line + } + + if constexpr (USE_RELATIVISTIC_DOPPLER_SHIFT) { + // With special relativity, the Doppler shift formula has an extra factor of 1/gamma in it, + // which changes the distance reach a line resonance and creates a dependence + // on packet position and direction + + // use linear interpolation of frequency along the path + return (nu_trans - nu_cmf) / d_nu_on_d_l; + } + return CLIGHT * prop_time * (nu_cmf / nu_trans - 1); +} #endif // RPKT_H diff --git a/scripts/artis-juwels.sh b/scripts/artis-juwels.sh index 296aba188..08d8b05c8 100755 --- a/scripts/artis-juwels.sh +++ b/scripts/artis-juwels.sh @@ -10,8 +10,9 @@ #SBATCH --mail-type=ALL ##SBATCH --mail-user=luke.shingles@gmail.com -module load Stages/2023 GCC ParaStationMPI -module load GSL +module load Stages/2024 GCC ParaStationMPI GSL + +module list cd $SLURM_SUBMIT_DIR diff --git a/scripts/artis-virgo-submit.sh b/scripts/artis-virgo-submit.sh index 887b76c8d..8d924a973 100755 --- a/scripts/artis-virgo-submit.sh +++ b/scripts/artis-virgo-submit.sh @@ -1,6 +1,6 @@ #!/bin/bash -x # 1920 cores and 4GB per core for 3D LTE kilonova models (and maybe 3D NLTE Type Ia?) -sbatch -J $(basename $(exec pwd)) --ntasks=1920 --mem-per-cpu=4096MB --partition=long --time=48:00:00 --constraint=intel --mail-type=ALL --mail-user=${USER}@gsi.de --no-requeue -- artis/scripts/artis-virgo-slurmjob.sh +sbatch -J $(basename $(exec pwd)) --ntasks=1920 --mem-per-cpu=4096MB --partition=long --time=48:00:00 --constraint=amd --mail-type=ALL --mail-user=${USER}@gsi.de --no-requeue -- artis/scripts/artis-virgo-slurmjob.sh # 960 cores and 1.5GB per core for simple 1D models (maybe 3D Type Ia without full NLTE?) #sbatch -J $(basename $(exec pwd)) --ntasks=960 --mem-per-cpu=1536M --partition=long --time=48:00:00 --constraint=amd --mail-type=ALL --mail-user=${USER}@gsi.de --no-requeue -- artis/scripts/artis-virgo-slurmjob.sh diff --git a/scripts/exspec-after.sh b/scripts/exspec-after.sh index 25080dde4..5c336b625 100755 --- a/scripts/exspec-after.sh +++ b/scripts/exspec-after.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# don't compress the files if we didn't successfully run exspec +# only compress the files if we successfully ran exspec if [ -f emission.out* ]; then if command -v zstd > /dev/null; then diff --git a/scripts/exspec-gzip-juwels.sh b/scripts/exspec-gzip-juwels.sh index aa8b3c070..070bd74c4 100755 --- a/scripts/exspec-gzip-juwels.sh +++ b/scripts/exspec-gzip-juwels.sh @@ -9,9 +9,7 @@ #SBATCH --mail-type=ALL ##SBATCH --mail-user=luke.shingles@gmail.com -module load Stages/2023 GCC ParaStationMPI GSL - -export PATH="/p/software/juwels/stages/2022/software/zstd/1.5.0-GCCcore-11.2.0/bin/:$PATH" +module load Stages/2023 GCC ParaStationMPI GSL zstd/.1.5.2 cd $SLURM_SUBMIT_DIR diff --git a/sn3d.cc b/sn3d.cc index ecdf03807..0125d0279 100644 --- a/sn3d.cc +++ b/sn3d.cc @@ -12,6 +12,8 @@ #include "sn3d.h" +#include + #include "atomic.h" #include "decay.h" #include "gammapkt.h" @@ -32,9 +34,7 @@ // threadprivate variables int tid; bool use_cellhist; -bool neutral_flag; -gsl_rng *rng = nullptr; -std::mt19937_64 *stdrng = nullptr; +std::mt19937 stdrng(std::random_device{}()); gsl_integration_workspace *gslworkspace = nullptr; FILE *output_file = nullptr; static FILE *linestat_file = nullptr; @@ -91,15 +91,15 @@ static void write_deposition_file(const int nts, const int my_rank, const int ns // for (int i = 0; i <= nts; i++) const int i = nts; { - const double t_mid = globals::time_step[i].mid; + const double t_mid = globals::timesteps[i].mid; // power in [erg/s] - globals::time_step[i].eps_positron_ana_power = 0.; - globals::time_step[i].eps_electron_ana_power = 0.; - globals::time_step[i].eps_alpha_ana_power = 0.; - globals::time_step[i].qdot_betaminus = 0.; - globals::time_step[i].qdot_alpha = 0.; - globals::time_step[i].qdot_total = 0.; + globals::timesteps[i].eps_positron_ana_power = 0.; + globals::timesteps[i].eps_electron_ana_power = 0.; + globals::timesteps[i].eps_alpha_ana_power = 0.; + globals::timesteps[i].qdot_betaminus = 0.; + globals::timesteps[i].qdot_alpha = 0.; + globals::timesteps[i].qdot_total = 0.; for (int mgi = nstart; mgi < (nstart + ndo); mgi++) // for (int mgi = 0; mgi < grid::get_npts_model(); mgi++) @@ -107,25 +107,25 @@ static void write_deposition_file(const int nts, const int my_rank, const int ns if (grid::get_numassociatedcells(mgi) > 0) { const double cellmass = grid::get_rho_tmin(mgi) * grid::get_modelcell_assocvolume_tmin(mgi); - globals::time_step[i].eps_positron_ana_power += + globals::timesteps[i].eps_positron_ana_power += cellmass * decay::get_particle_injection_rate(mgi, t_mid, decay::DECAYTYPE_BETAPLUS); - globals::time_step[i].eps_electron_ana_power += + globals::timesteps[i].eps_electron_ana_power += cellmass * decay::get_particle_injection_rate(mgi, t_mid, decay::DECAYTYPE_BETAMINUS); - globals::time_step[i].eps_alpha_ana_power += + globals::timesteps[i].eps_alpha_ana_power += cellmass * decay::get_particle_injection_rate(mgi, t_mid, decay::DECAYTYPE_ALPHA); if (i == nts) { mtot += cellmass; } - for (int dectypeindex = 0; dectypeindex < decay::DECAYTYPE_COUNT; dectypeindex++) { + for (const auto decaytype : decay::all_decaytypes) { // Qdot here has been multiplied by mass, so it is in units of [erg/s] - const double qdot_cell = decay::get_qdot_modelcell(mgi, t_mid, dectypeindex) * cellmass; - globals::time_step[i].qdot_total += qdot_cell; - if (dectypeindex == decay::DECAYTYPE_BETAMINUS) { - globals::time_step[i].qdot_betaminus += qdot_cell; - } else if (dectypeindex == decay::DECAYTYPE_ALPHA) { - globals::time_step[i].qdot_alpha += qdot_cell; + const double qdot_cell = decay::get_qdot_modelcell(mgi, t_mid, decaytype) * cellmass; + globals::timesteps[i].qdot_total += qdot_cell; + if (decaytype == decay::DECAYTYPE_BETAMINUS) { + globals::timesteps[i].qdot_betaminus += qdot_cell; + } else if (decaytype == decay::DECAYTYPE_ALPHA) { + globals::timesteps[i].qdot_alpha += qdot_cell; } } } @@ -133,12 +133,12 @@ static void write_deposition_file(const int nts, const int my_rank, const int ns #ifdef MPI_ON // in MPI mode, each process only did some fraction of the cells - MPI_Allreduce(MPI_IN_PLACE, &globals::time_step[i].eps_positron_ana_power, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(MPI_IN_PLACE, &globals::time_step[i].eps_electron_ana_power, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(MPI_IN_PLACE, &globals::time_step[i].eps_alpha_ana_power, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(MPI_IN_PLACE, &globals::time_step[i].qdot_betaminus, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(MPI_IN_PLACE, &globals::time_step[i].qdot_alpha, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(MPI_IN_PLACE, &globals::time_step[i].qdot_total, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(MPI_IN_PLACE, &globals::timesteps[i].eps_positron_ana_power, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(MPI_IN_PLACE, &globals::timesteps[i].eps_electron_ana_power, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(MPI_IN_PLACE, &globals::timesteps[i].eps_alpha_ana_power, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(MPI_IN_PLACE, &globals::timesteps[i].qdot_betaminus, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(MPI_IN_PLACE, &globals::timesteps[i].qdot_alpha, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(MPI_IN_PLACE, &globals::timesteps[i].qdot_total, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); #endif } @@ -156,26 +156,26 @@ static void write_deposition_file(const int nts, const int my_rank, const int ns "Qdot_betaminus_ana_erg/s/g Qdotalpha_ana_erg/s/g eps_erg/s/g Qdot_ana_erg/s/g\n"); for (int i = 0; i <= nts; i++) { - const double t_mid = globals::time_step[i].mid; - const double t_width = globals::time_step[i].width; - const double total_dep = (globals::time_step[i].gamma_dep + globals::time_step[i].positron_dep + - globals::time_step[i].electron_dep + globals::time_step[i].alpha_dep); + const double t_mid = globals::timesteps[i].mid; + const double t_width = globals::timesteps[i].width; + const double total_dep = (globals::timesteps[i].gamma_dep + globals::timesteps[i].positron_dep + + globals::timesteps[i].electron_dep + globals::timesteps[i].alpha_dep); // dep is used here for positrons and alphas because it is the same as the emission rate - const double epsilon_mc = (globals::time_step[i].gamma_emission + globals::time_step[i].positron_dep + - globals::time_step[i].electron_emission + globals::time_step[i].alpha_emission) / + const double epsilon_mc = (globals::timesteps[i].gamma_emission + globals::timesteps[i].positron_dep + + globals::timesteps[i].electron_emission + globals::timesteps[i].alpha_emission) / mtot / t_width; fprintf(dep_file, "%d %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g\n", i, t_mid / DAY, t_mid, - total_dep / t_width / LSUN, globals::time_step[i].gamma_dep / t_width / LSUN, - globals::time_step[i].gamma_dep_pathint / t_width / LSUN, - globals::time_step[i].positron_dep / t_width / LSUN, globals::time_step[i].eps_positron_ana_power / LSUN, - globals::time_step[i].electron_dep / t_width / LSUN, - globals::time_step[i].electron_emission / t_width / LSUN, - globals::time_step[i].eps_electron_ana_power / LSUN, globals::time_step[i].alpha_dep / t_width / LSUN, - globals::time_step[i].alpha_emission / t_width / LSUN, globals::time_step[i].eps_alpha_ana_power / LSUN, - globals::time_step[i].gamma_emission / t_width / LSUN, globals::time_step[i].qdot_betaminus / mtot, - globals::time_step[i].qdot_alpha / mtot, epsilon_mc, globals::time_step[i].qdot_total / mtot); + total_dep / t_width / LSUN, globals::timesteps[i].gamma_dep / t_width / LSUN, + globals::timesteps[i].gamma_dep_pathint / t_width / LSUN, + globals::timesteps[i].positron_dep / t_width / LSUN, globals::timesteps[i].eps_positron_ana_power / LSUN, + globals::timesteps[i].electron_dep / t_width / LSUN, + globals::timesteps[i].electron_emission / t_width / LSUN, + globals::timesteps[i].eps_electron_ana_power / LSUN, globals::timesteps[i].alpha_dep / t_width / LSUN, + globals::timesteps[i].alpha_emission / t_width / LSUN, globals::timesteps[i].eps_alpha_ana_power / LSUN, + globals::timesteps[i].gamma_emission / t_width / LSUN, globals::timesteps[i].qdot_betaminus / mtot, + globals::timesteps[i].qdot_alpha / mtot, epsilon_mc, globals::timesteps[i].qdot_total / mtot); } fclose(dep_file); @@ -205,17 +205,17 @@ static void mpi_communicate_grid_properties(const int my_rank, const int nprocs, if (grid::get_numassociatedcells(modelgridindex) > 0) { nonthermal::nt_MPI_Bcast(modelgridindex, root); - if (NLTE_POPS_ON && globals::rank_in_node == 0) { + if (globals::total_nlte_levels > 0 && globals::rank_in_node == 0) { MPI_Bcast(grid::modelgrid[modelgridindex].nlte_pops, globals::total_nlte_levels, MPI_DOUBLE, root_node_id, globals::mpi_comm_internode); } if constexpr (USE_LUT_PHOTOION) { assert_always(globals::corrphotoionrenorm != nullptr); - MPI_Bcast(&globals::corrphotoionrenorm[modelgridindex * get_nelements() * get_max_nions()], + MPI_Bcast(&globals::corrphotoionrenorm[get_ionestimindex(modelgridindex, 0, 0)], get_nelements() * get_max_nions(), MPI_DOUBLE, root, MPI_COMM_WORLD); assert_always(globals::gammaestimator != nullptr); - MPI_Bcast(&globals::gammaestimator[modelgridindex * get_nelements() * get_max_nions()], + MPI_Bcast(&globals::gammaestimator[get_ionestimindex(modelgridindex, 0, 0)], get_nelements() * get_max_nions(), MPI_DOUBLE, root, MPI_COMM_WORLD); } } @@ -345,23 +345,23 @@ static void mpi_reduce_estimators(int nts) { MPI_Barrier(MPI_COMM_WORLD); /// Communicate gamma and positron deposition and write to file - MPI_Allreduce(MPI_IN_PLACE, &globals::time_step[nts].cmf_lum, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(MPI_IN_PLACE, &globals::time_step[nts].gamma_dep, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(MPI_IN_PLACE, &globals::time_step[nts].positron_dep, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(MPI_IN_PLACE, &globals::time_step[nts].electron_dep, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(MPI_IN_PLACE, &globals::time_step[nts].electron_emission, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(MPI_IN_PLACE, &globals::time_step[nts].alpha_dep, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(MPI_IN_PLACE, &globals::time_step[nts].alpha_emission, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(MPI_IN_PLACE, &globals::time_step[nts].gamma_emission, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - - globals::time_step[nts].cmf_lum /= globals::nprocs; - globals::time_step[nts].gamma_dep /= globals::nprocs; - globals::time_step[nts].positron_dep /= globals::nprocs; - globals::time_step[nts].electron_dep /= globals::nprocs; - globals::time_step[nts].electron_emission /= globals::nprocs; - globals::time_step[nts].alpha_dep /= globals::nprocs; - globals::time_step[nts].alpha_emission /= globals::nprocs; - globals::time_step[nts].gamma_emission /= globals::nprocs; + MPI_Allreduce(MPI_IN_PLACE, &globals::timesteps[nts].cmf_lum, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(MPI_IN_PLACE, &globals::timesteps[nts].gamma_dep, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(MPI_IN_PLACE, &globals::timesteps[nts].positron_dep, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(MPI_IN_PLACE, &globals::timesteps[nts].electron_dep, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(MPI_IN_PLACE, &globals::timesteps[nts].electron_emission, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(MPI_IN_PLACE, &globals::timesteps[nts].alpha_dep, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(MPI_IN_PLACE, &globals::timesteps[nts].alpha_emission, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(MPI_IN_PLACE, &globals::timesteps[nts].gamma_emission, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + + globals::timesteps[nts].cmf_lum /= globals::nprocs; + globals::timesteps[nts].gamma_dep /= globals::nprocs; + globals::timesteps[nts].positron_dep /= globals::nprocs; + globals::timesteps[nts].electron_dep /= globals::nprocs; + globals::timesteps[nts].electron_emission /= globals::nprocs; + globals::timesteps[nts].alpha_dep /= globals::nprocs; + globals::timesteps[nts].alpha_emission /= globals::nprocs; + globals::timesteps[nts].gamma_emission /= globals::nprocs; if constexpr (TRACK_ION_STATS) { stats::reduce_estimators(); @@ -466,25 +466,7 @@ static void save_grid_and_packets(const int nts, const int my_rank, struct packe // save packet state at start of current timestep (before propagation) write_temp_packetsfile(nts, my_rank, packets); - if constexpr (VPKT_ON) { - char filename[MAXFILENAMELENGTH]; - snprintf(filename, MAXFILENAMELENGTH, "vspecpol_%d_%d_%s.tmp", 0, my_rank, (nts % 2 == 0) ? "even" : "odd"); - - FILE *vspecpol_file = fopen_required(filename, "wb"); - - write_vspecpol(vspecpol_file); - fclose(vspecpol_file); - - // Write temporary files for vpkt_grid - if (vgrid_flag == 1) { - snprintf(filename, MAXFILENAMELENGTH, "vpkt_grid_%d_%d_%s.tmp", 0, my_rank, (nts % 2 == 0) ? "even" : "odd"); - - FILE *vpkt_grid_file = fopen_required(filename, "wb"); - - write_vpkt_grid(vpkt_grid_file); - fclose(vpkt_grid_file); - } - } + vpkt_write_timestep(nts, my_rank, tid, false); const time_t time_write_packets_file_finished = time(nullptr); @@ -531,6 +513,7 @@ static void save_grid_and_packets(const int nts, const int my_rank, struct packe // delete temp packets files from previous timestep now that all restart data for the new timestep is available remove_temp_packetsfile(nts - 1, my_rank); + vpkt_remove_temp_file(nts - 1, my_rank); } } @@ -550,10 +533,10 @@ static void zero_estimators() { for (int element = 0; element < get_nelements(); element++) { for (int ion = 0; ion < get_max_nions(); ion++) { if constexpr (USE_LUT_PHOTOION) { - globals::gammaestimator[n * get_nelements() * get_max_nions() + element * get_max_nions() + ion] = 0.; + globals::gammaestimator[get_ionestimindex(n, element, ion)] = 0.; } if constexpr (USE_LUT_BFHEATING) { - globals::bfheatingestimator[n * get_nelements() * get_max_nions() + element * get_max_nions() + ion] = 0.; + globals::bfheatingestimator[get_ionestimindex(n, element, ion)] = 0.; } } } @@ -568,7 +551,7 @@ static auto do_timestep(const int nts, const int titer, const int my_rank, const bool do_this_full_loop = true; const int nts_prev = (titer != 0 || nts == 0) ? nts : nts - 1; - if ((titer > 0) || (globals::simulation_continued_from_saved && (nts == globals::itstep))) { + if ((titer > 0) || (globals::simulation_continued_from_saved && (nts == globals::timestep_initial))) { /// Read the packets file to reset before each additional iteration on the timestep read_temp_packetsfile(nts, my_rank, packets); } @@ -605,7 +588,7 @@ static auto do_timestep(const int nts, const int titer, const int my_rank, const /// If this is not the 0th time step of the current job step, /// write out a snapshot of the grid properties for further restarts /// and update input.txt accordingly - if (((nts - globals::itstep) != 0)) { + if (((nts - globals::timestep_initial) != 0)) { save_grid_and_packets(nts, my_rank, packets); do_this_full_loop = walltime_sufficient_to_continue(nts, nts_prev, walltimelimitseconds); } @@ -617,7 +600,7 @@ static auto do_timestep(const int nts, const int titer, const int my_rank, const zero_estimators(); // MPI_Barrier(MPI_COMM_WORLD); - if ((nts < globals::ftstep) && do_this_full_loop) { + if ((nts < globals::timestep_finish) && do_this_full_loop) { /// Now process the packets. update_packets(my_rank, nts, packets); @@ -646,9 +629,9 @@ static auto do_timestep(const int nts, const int titer, const int my_rank, const #endif printout("During timestep %d on MPI process %d, %d pellets decayed and %d packets escaped. (t=%gd)\n", nts, my_rank, - globals::time_step[nts].pellet_decays, globals::nesc, globals::time_step[nts].mid / DAY); + globals::timesteps[nts].pellet_decays.load(), globals::nesc.load(), globals::timesteps[nts].mid / DAY); - if constexpr (VPKT_ON) { + if (VPKT_ON) { printout("During timestep %d on MPI process %d, %d virtual packets were generated and %d escaped. \n", nts, my_rank, nvpkt, nvpkt_esc1 + nvpkt_esc2 + nvpkt_esc3); printout( @@ -679,27 +662,13 @@ static auto do_timestep(const int nts, const int titer, const int my_rank, const } } - if (nts == globals::ftstep - 1) { + if (nts == globals::timestep_finish - 1) { char filename[MAXFILENAMELENGTH]; snprintf(filename, MAXFILENAMELENGTH, "packets%.2d_%.4d.out", 0, my_rank); // snprintf(filename, MAXFILENAMELENGTH, "packets%.2d_%.4d.out", middle_iteration, my_rank); write_packets(filename, packets); - // write specpol of the virtual packets - if constexpr (VPKT_ON) { - snprintf(filename, MAXFILENAMELENGTH, "vspecpol_%d-%d.out", my_rank, tid); - FILE *vspecpol_file = fopen_required(filename, "w"); - - write_vspecpol(vspecpol_file); - fclose(vspecpol_file); - - if (vgrid_flag == 1) { - snprintf(filename, MAXFILENAMELENGTH, "vpkt_grid_%d-%d.out", my_rank, tid); - FILE *vpkt_grid_file = fopen_required(filename, "w"); - write_vpkt_grid(vpkt_grid_file); - fclose(vpkt_grid_file); - } - } + vpkt_write_timestep(nts, my_rank, tid, true); printout("time after write final packets file %ld\n", time(nullptr)); @@ -730,42 +699,12 @@ auto main(int argc, char *argv[]) -> int { #ifdef MPI_ON MPI_Init(&argc, &argv); - MPI_Comm_rank(MPI_COMM_WORLD, &globals::rank_global); - MPI_Comm_size(MPI_COMM_WORLD, &globals::nprocs); - - // make an intra-node communicator (group ranks that can share memory) - MPI_Comm_split_type(MPI_COMM_WORLD, MPI_COMM_TYPE_SHARED, globals::rank_global, MPI_INFO_NULL, - &globals::mpi_comm_node); - // get the local rank within this node - MPI_Comm_rank(globals::mpi_comm_node, &globals::rank_in_node); - // get the number of ranks on the node - MPI_Comm_size(globals::mpi_comm_node, &globals::node_nprocs); - MPI_Barrier(MPI_COMM_WORLD); - - // make an inter-node communicator (using local rank as the key for group membership) - MPI_Comm_split(MPI_COMM_WORLD, globals::rank_in_node, globals::rank_global, &globals::mpi_comm_internode); - - // take the node id from the local rank 0 (node master) and broadcast it - if (globals::rank_in_node == 0) { - MPI_Comm_rank(globals::mpi_comm_internode, &globals::node_id); - MPI_Comm_size(globals::mpi_comm_internode, &globals::node_count); - } - - MPI_Bcast(&globals::node_id, 1, MPI_INT, 0, globals::mpi_comm_node); - MPI_Bcast(&globals::node_count, 1, MPI_INT, 0, globals::mpi_comm_node); - -#else - globals::rank_global = 0; - globals::nprocs = 1; - globals::rank_in_node = 0; - globals::node_nprocs = 1; - globals::node_id = 0; - globals::node_count = 0; #endif - const int my_rank = globals::rank_global; + globals::setup_mpi_vars(); - if (my_rank == 0) { + globals::startofline = std::make_unique(get_max_threads()); + if (globals::rank_global == 0) { check_already_running(); } @@ -774,7 +713,7 @@ auto main(int argc, char *argv[]) -> int { MPI_Barrier(MPI_COMM_WORLD); #endif - globals::startofline = std::make_unique(get_max_threads()); + const int my_rank = globals::rank_global; #ifdef _OPENMP /// Explicitly turn off dynamic threads because we use the threadprivate directive!!! @@ -795,7 +734,7 @@ auto main(int argc, char *argv[]) -> int { #ifdef _OPENMP printout("OpenMP parallelisation active with %d threads (max %d)\n", get_num_threads(), get_max_threads()); #else - printout("OpenMP is not available in this build\n"); + printout("OpenMP is not enabled in this build (this is normal)\n"); #endif gslworkspace = gsl_integration_workspace_alloc(GSLWSIZE); @@ -818,7 +757,7 @@ auto main(int argc, char *argv[]) -> int { printout("walltimelimitseconds = %d\n", walltimelimitseconds); } else { fprintf(stderr, "Usage: %s [-w WALLTIMELIMITHOURS]\n", argv[0]); - exit(EXIT_FAILURE); + abort(); } } @@ -850,18 +789,23 @@ auto main(int argc, char *argv[]) -> int { printout("MPI is disabled in this build\n"); #endif - globals::kappa_rpkt_cont = - static_cast(calloc(get_max_threads(), sizeof(struct rpkt_cont_opacity))); - assert_always(globals::kappa_rpkt_cont != nullptr); + globals::chi_rpkt_cont = static_cast( + calloc(get_max_threads(), sizeof(struct rpkt_continuum_absorptioncoeffs))); + assert_always(globals::chi_rpkt_cont != nullptr); input(my_rank); + if (globals::simulation_continued_from_saved) { + assert_always(globals::nprocs_exspec == globals::nprocs); + } else { + globals::nprocs_exspec = globals::nprocs; + } if (my_rank == 0) { initialise_linestat_file(); } printout("time after input %ld\n", time(nullptr)); - printout("timesteps %d\n", globals::ntstep); + printout("timesteps %d\n", globals::ntimesteps); /// Precalculate the rate coefficients for spontaneous and stimulated recombination /// and for photoionisation. With the nebular approximation they only depend on T_e @@ -916,9 +860,9 @@ auto main(int argc, char *argv[]) -> int { /// The next loop is over all grid cells. For parallelisation, we want to split this loop between /// processes. This is done by assigning each MPI process nblock cells. The residual n_leftover /// cells are sent to processes 0 ... process n_leftover -1. - int const nstart = grid::get_nstart(my_rank); - int const ndo = grid::get_ndo(my_rank); - int const ndo_nonempty = grid::get_ndo_nonempty(my_rank); + const int nstart = grid::get_nstart(my_rank); + const int ndo = grid::get_ndo(my_rank); + const int ndo_nonempty = grid::get_ndo_nonempty(my_rank); printout("process rank %d (global max rank %d) assigned %d modelgrid cells (%d nonempty)", my_rank, globals::nprocs - 1, ndo, ndo_nonempty); if (ndo > 0) { @@ -929,7 +873,7 @@ auto main(int argc, char *argv[]) -> int { #ifdef MPI_ON MPI_Barrier(MPI_COMM_WORLD); - int const maxndo = grid::get_maxndo(); + const int maxndo = grid::get_maxndo(); /// Initialise the exchange buffer /// The factor 4 comes from the fact that our buffer should contain elements of 4 byte /// instead of 1 byte chars. But the MPI routines don't care about the buffers datatype @@ -940,7 +884,7 @@ auto main(int argc, char *argv[]) -> int { MPI_Barrier(MPI_COMM_WORLD); #endif - int nts = globals::itstep; + int nts = globals::timestep_initial; macroatom_open_file(my_rank); if (ndo > 0) { @@ -948,41 +892,16 @@ auto main(int argc, char *argv[]) -> int { snprintf(filename, MAXFILENAMELENGTH, "estimators_%.4d.out", my_rank); estimators_file = fopen_required(filename, "w"); - if (NLTE_POPS_ON && ndo_nonempty > 0) { + if (globals::total_nlte_levels > 0 && ndo_nonempty > 0) { nltepop_open_file(my_rank); } } - // Initialise virtual packets file and vspecpol - if constexpr (VPKT_ON) { - init_vspecpol(); - if (vgrid_flag == 1) { - init_vpkt_grid(); - } - - if (globals::simulation_continued_from_saved) { - // Continue simulation: read into temporary files - - read_vspecpol(my_rank, nts); - - if (vgrid_flag == 1) { - if (nts % 2 == 0) { - snprintf(filename, MAXFILENAMELENGTH, "vpkt_grid_%d_%d_odd.tmp", 0, my_rank); - } else { - snprintf(filename, MAXFILENAMELENGTH, "vpkt_grid_%d_%d_even.tmp", 0, my_rank); - } + // initialise or read in virtual packet spectra + vpkt_init(nts, my_rank, tid, globals::simulation_continued_from_saved); - FILE *vpktgrid_file = fopen_required(filename, "rb"); - - read_vpkt_grid(vpktgrid_file); - - fclose(vpktgrid_file); - } - } - } - - while (nts < globals::ftstep && !terminate_early) { - globals::nts_global = nts; + while (nts < globals::timestep_finish && !terminate_early) { + globals::timestep = nts; #ifdef MPI_ON // const time_t time_before_barrier = time(nullptr); MPI_Barrier(MPI_COMM_WORLD); @@ -991,16 +910,12 @@ auto main(int argc, char *argv[]) -> int { // time_after_barrier); #endif -#ifdef DO_TITER - // The first time step must solve the ionisation balance in LTE - globals::initial_iteration = (nts == 0); -#else /// titer example: Do 3 iterations on timestep 0-6 // globals::n_titer = (nts < 6) ? 3: 1; globals::n_titer = 1; - globals::initial_iteration = (nts < globals::num_lte_timesteps); -#endif + globals::lte_iteration = (nts < globals::num_lte_timesteps); + assert_always(globals::num_lte_timesteps > 0); // The first time step must solve the ionisation balance in LTE for (int titer = 0; titer < globals::n_titer; titer++) { terminate_early = do_timestep(nts, titer, my_rank, nstart, ndo, packets, walltimelimitseconds); @@ -1027,7 +942,7 @@ auto main(int argc, char *argv[]) -> int { fclose(linestat_file); } - if ((globals::ntstep != globals::ftstep) || (terminate_early)) { + if ((globals::ntimesteps != globals::timestep_finish) || (terminate_early)) { printout("RESTART_NEEDED to continue model\n"); } else { printout("No need for restart\n"); @@ -1038,7 +953,7 @@ auto main(int argc, char *argv[]) -> int { #endif const time_t real_time_end = time(nullptr); - printout("simulation finished at %ld (this job wallclock hours %.2f * %d CPUs = %.1f CPU hours)\n", real_time_end, + printout("sn3d finished at %ld (this job wallclock hours %.2f * %d CPUs = %.1f CPU hours)\n", real_time_end, (real_time_end - real_time_start) / 3600., globals::nprocs, (real_time_end - real_time_start) / 3600. * globals::nprocs); @@ -1047,9 +962,7 @@ auto main(int argc, char *argv[]) -> int { } macroatom_close_file(); - if (NLTE_POPS_ON) { - nltepop_close_file(); - } + nltepop_close_file(); radfield::close_file(); nonthermal::close_file(); @@ -1076,8 +989,9 @@ auto main(int argc, char *argv[]) -> int { MPI_Finalize(); #endif - if (std::filesystem::exists("artis.pid")) { - std::filesystem::remove("artis.pid"); + const std::filesystem::path pid_file_path("artis.pid"); + if (std::filesystem::exists(pid_file_path)) { + std::filesystem::remove(pid_file_path); } return 0; diff --git a/sn3d.h b/sn3d.h index f2b7a8998..09067bba3 100644 --- a/sn3d.h +++ b/sn3d.h @@ -7,12 +7,9 @@ #include #include -#include #include -#include #include #include -#include #include #include #include @@ -33,17 +30,13 @@ extern FILE *output_file; extern int tid; extern bool use_cellhist; -extern bool neutral_flag; -#include -extern gsl_rng *rng; // pointer for random number generator -extern std::mt19937_64 *stdrng; -static std::uniform_real_distribution stdrngdis(0.0, 1.0); +extern std::mt19937 stdrng; extern gsl_integration_workspace *gslworkspace; #ifdef _OPENMP -#pragma omp threadprivate(tid, use_cellhist, neutral_flag, rng, gslworkspace, output_file) +#pragma omp threadprivate(tid, use_cellhist, stdrng, gslworkspace, output_file) #endif #define __artis_assert(e) \ @@ -115,7 +108,7 @@ static inline int get_bflutindex(const int tempindex, const int element, const i #ifdef _OPENMP #define safeadd(var, val) _Pragma("omp atomic update") var += val #else -#define safeadd(var, val) var += val +#define safeadd(var, val) var = var + val #endif #define safeincrement(var) safeadd(var, 1) @@ -130,28 +123,41 @@ static inline void gsl_error_handler_printout(const char *reason, const char *fi } } -static FILE *fopen_required(const char *filename, const char *mode) { - assert_always(filename != nullptr); - std::string datafolderfilename("data/"); - datafolderfilename += filename; +static FILE *fopen_required(const std::string &filename, const char *mode) { + // look in the data folder first + const std::string datafolderfilename = "data/" + filename; if (mode[0] == 'r' && std::filesystem::exists(datafolderfilename)) { - return fopen_required(datafolderfilename.c_str(), mode); + return fopen_required(datafolderfilename, mode); } - FILE *file = std::fopen(filename, mode); + + FILE *file = std::fopen(filename.c_str(), mode); if (file == nullptr) { - printout("ERROR: Could not open file '%s' for mode '%s'.\n", filename, mode); + printout("ERROR: Could not open file '%s' for mode '%s'.\n", filename.c_str(), mode); abort(); } return file; } +static std::fstream fstream_required(const std::string &filename, std::ios_base::openmode mode) { + const std::string datafolderfilename = "data/" + filename; + if (mode == std::ios::in && std::filesystem::exists(datafolderfilename)) { + return fstream_required(datafolderfilename, mode); + } + auto file = std::fstream(filename, mode); + if (!file.is_open()) { + printout("ERROR: Could not open file '%s'\n", filename.c_str()); + abort(); + } + return file; +} + static int get_timestep(const double time) { assert_always(time >= globals::tmin); assert_always(time < globals::tmax); - for (int nts = 0; nts < globals::ntstep; nts++) { - const double tsend = (nts < (globals::ntstep - 1)) ? globals::time_step[nts + 1].start : globals::tmax; - if (time >= globals::time_step[nts].start && time < tsend) { + for (int nts = 0; nts < globals::ntimesteps; nts++) { + const double tsend = (nts < (globals::ntimesteps - 1)) ? globals::timesteps[nts + 1].start : globals::tmax; + if (time >= globals::timesteps[nts].start && time < tsend) { return nts; } } @@ -184,35 +190,25 @@ inline int get_thread_num(void) { #endif } -inline double rng_uniform(void) { - if constexpr (USE_GSL_RANDOM) { - return gsl_rng_uniform(rng); - } else { - return stdrngdis(*stdrng); - } +inline float rng_uniform(void) { + float zrand; + do { + zrand = std::generate_canonical::digits>(stdrng); + } while (zrand == 1.); + return zrand; } -inline double rng_uniform_pos(void) { - if constexpr (USE_GSL_RANDOM) { - return gsl_rng_uniform_pos(rng); - } else { - double zrand = 0.; - do { - zrand = rng_uniform(); - } while (zrand <= 0.); - return zrand; - } +inline float rng_uniform_pos(void) { + float zrand = 0.; + do { + zrand = rng_uniform(); + } while (zrand <= 0.); + return zrand; } inline void rng_init(const uint_fast64_t zseed) { - if constexpr (USE_GSL_RANDOM) { - rng = gsl_rng_alloc(gsl_rng_ran3); - gsl_rng_set(rng, zseed); - printout("rng is a '%s' generator\n", gsl_rng_name(rng)); - } else { - printout("rng is a std::mt19937_64 generator\n"); - stdrng = new std::mt19937_64(zseed); - } + printout("rng is a std::mt19937 generator\n"); + stdrng.seed(zseed); } inline bool is_pid_running(pid_t pid) { @@ -229,7 +225,7 @@ inline void check_already_running(void) { pid_t artispid = getpid(); if (std::filesystem::exists("artis.pid")) { - std::ifstream pidfile("artis.pid", std::ifstream::in); + auto pidfile = std::fstream("artis.pid", std::ios::in); pid_t artispid_in; pidfile >> artispid_in; pidfile.close(); @@ -243,9 +239,13 @@ inline void check_already_running(void) { } } - std::ofstream pidfile("artis.pid", std::ofstream::out | std::ofstream::trunc); + auto pidfile = std::fstream("artis.pid", std::ofstream::out | std::ofstream::trunc); pidfile << artispid; pidfile.close(); } +inline int get_ionestimindex(const int mgi, const int element, const int ion) { + return mgi * get_nelements() * get_max_nions() + element * get_max_nions() + ion; +} + #endif // SN3D_H diff --git a/spectrum.cc b/spectrum.cc index c5c1af5f8..1417121f9 100644 --- a/spectrum.cc +++ b/spectrum.cc @@ -4,6 +4,7 @@ #include #include #include +#include #include "atomic.h" #include "exspec.h" @@ -28,37 +29,11 @@ using emissionabsorptioncontrib = struct emissionabsorptioncontrib { int lineindex; // this will be important when the list gets sorted }; -static struct emissionabsorptioncontrib *traceemissionabsorption = nullptr; +static std::vector traceemissionabsorption; double traceemission_totalenergy = 0.; double traceabsorption_totalenergy = 0.; -std::unique_ptr rpkt_spectra = nullptr; - -static auto compare_emission(const void *p1, const void *p2) -> int { - const auto *elem1 = static_cast(p1); - const auto *elem2 = static_cast(p2); - - if (elem1->energyemitted < elem2->energyemitted) { - return 1; - } - if (elem1->energyemitted > elem2->energyemitted) { - return -1; - } - return 0; -} - -static auto compare_absorption(const void *p1, const void *p2) -> int { - const auto *elem1 = static_cast(p1); - const auto *elem2 = static_cast(p2); - - if (elem1->energyabsorbed < elem2->energyabsorbed) { - return 1; - } - if (elem1->energyabsorbed > elem2->energyabsorbed) { - return -1; - } - return 0; -} +struct spec rpkt_spectra; static void printout_tracemission_stats() { const int maxlinesprinted = 500; @@ -66,7 +41,8 @@ static void printout_tracemission_stats() { // mode is 0 for emission and 1 for absorption for (int mode = 0; mode < 2; mode++) { if (mode == 0) { - qsort(traceemissionabsorption, globals::nlines, sizeof(emissionabsorptioncontrib), compare_emission); + std::sort(traceemissionabsorption.begin(), traceemissionabsorption.end(), + [](const auto &a, const auto &b) { return a.energyemitted > b.energyemitted; }); printout("lambda [%5.1f, %5.1f] nu %g %g\n", traceemissabs_lambdamin, traceemissabs_lambdamax, traceemissabs_nulower, traceemissabs_nuupper); @@ -74,7 +50,8 @@ static void printout_tracemission_stats() { traceemissabs_lambdamin, traceemissabs_lambdamax, traceemissabs_timemin / DAY, traceemissabs_timemax / DAY, traceemission_totalenergy); } else { - qsort(traceemissionabsorption, globals::nlines, sizeof(emissionabsorptioncontrib), compare_absorption); + std::sort(traceemissionabsorption.begin(), traceemissionabsorption.end(), + [](const auto &a, const auto &b) { return a.energyabsorbed > b.energyabsorbed; }); printout("Top line absorption contributions in the range lambda [%5.1f, %5.1f] time [%5.1fd, %5.1fd] (%g erg)\n", traceemissabs_lambdamin, traceemissabs_lambdamax, traceemissabs_timemin / DAY, traceemissabs_timemax / DAY, traceabsorption_totalenergy); @@ -127,7 +104,7 @@ static void printout_tracemission_stats() { const int nupperdowntrans = get_ndowntrans(element, ion, upper); auto *downtranslist = globals::elements[element].ions[ion].levels[upper].downtrans; auto *downtrans = std::find_if(downtranslist, downtranslist + nupperdowntrans, - [=](auto &downtrans) { return downtrans.targetlevelindex == lower; }); + [=](const auto &downtrans) { return downtrans.targetlevelindex == lower; }); assert_always(downtrans != (downtranslist + nupperdowntrans)); printout("%7.2e (%5.1f%%) %4d %9d %5d %5d %8.1f %8.2e %4d %7.1f %7.1f %7.1e %7.1e\n", encontrib, @@ -142,8 +119,7 @@ static void printout_tracemission_stats() { printout("\n"); } - free(traceemissionabsorption); - traceemissionabsorption = nullptr; + traceemissionabsorption.clear(); } static auto get_proccount() -> int @@ -152,15 +128,16 @@ static auto get_proccount() -> int return 2 * get_nelements() * get_max_nions() + 1; } -void write_spectrum(const std::string &spec_filename, const char *emission_filename, const char *trueemission_filename, - const char *absorption_filename, const struct spec &spectra, int numtimesteps) { - FILE *spec_file = fopen_required(spec_filename.c_str(), "w"); +void write_spectrum(const std::string &spec_filename, const std::string &emission_filename, + const std::string &trueemission_filename, const std::string &absorption_filename, + const struct spec &spectra, int numtimesteps) { + FILE *spec_file = fopen_required(spec_filename, "w"); FILE *emission_file = nullptr; FILE *trueemission_file = nullptr; FILE *absorption_file = nullptr; - bool const do_emission_res = spectra.do_emission_res; + const bool do_emission_res = spectra.do_emission_res; if (do_emission_res) { emission_file = fopen_required(emission_filename, "w"); @@ -169,21 +146,21 @@ void write_spectrum(const std::string &spec_filename, const char *emission_filen assert_always(trueemission_file != nullptr); absorption_file = fopen_required(absorption_filename, "w"); assert_always(absorption_file != nullptr); - printout("Writing %s, %s, %s, and %s\n", spec_filename.c_str(), emission_filename, trueemission_filename, - absorption_filename); + printout("Writing %s, %s, %s, and %s\n", spec_filename.c_str(), emission_filename.c_str(), + trueemission_filename.c_str(), absorption_filename.c_str()); } else { printout("Writing %s\n", spec_filename.c_str()); } - if (TRACE_EMISSION_ABSORPTION_REGION_ON && do_emission_res && traceemissionabsorption != nullptr) { + if (TRACE_EMISSION_ABSORPTION_REGION_ON && do_emission_res && !traceemissionabsorption.empty()) { printout_tracemission_stats(); } - assert_always(numtimesteps <= globals::ntstep); + assert_always(numtimesteps <= globals::ntimesteps); fprintf(spec_file, "%g ", 0.0); for (int p = 0; p < numtimesteps; p++) { - fprintf(spec_file, "%g ", globals::time_step[p].mid / DAY); + fprintf(spec_file, "%g ", globals::timesteps[p].mid / DAY); } fprintf(spec_file, "\n"); @@ -223,17 +200,17 @@ void write_spectrum(const std::string &spec_filename, const char *emission_filen } void write_specpol(const std::string &specpol_filename, const std::string &emission_filename, - const std::string &absorption_filename, struct spec *stokes_i, struct spec *stokes_q, - struct spec *stokes_u) { - FILE *specpol_file = fopen_required(specpol_filename.c_str(), "w"); + const std::string &absorption_filename, const struct spec *stokes_i, const struct spec *stokes_q, + const struct spec *stokes_u) { + FILE *specpol_file = fopen_required(specpol_filename, "w"); FILE *emissionpol_file = nullptr; FILE *absorptionpol_file = nullptr; const bool do_emission_res = stokes_i->do_emission_res; if (do_emission_res) { - emissionpol_file = fopen_required(emission_filename.c_str(), "w"); - absorptionpol_file = fopen_required(absorption_filename.c_str(), "w"); + emissionpol_file = fopen_required(emission_filename, "w"); + absorptionpol_file = fopen_required(absorption_filename, "w"); printout("Writing %s, %s, and %s\n", specpol_filename.c_str(), emission_filename.c_str(), absorption_filename.c_str()); } else { @@ -243,8 +220,8 @@ void write_specpol(const std::string &specpol_filename, const std::string &emiss fprintf(specpol_file, "%g ", 0.0); for (int l = 0; l < 3; l++) { - for (int p = 0; p < globals::ntstep; p++) { - fprintf(specpol_file, "%g ", globals::time_step[p].mid / DAY); + for (int p = 0; p < globals::ntimesteps; p++) { + fprintf(specpol_file, "%g ", globals::timesteps[p].mid / DAY); } } @@ -252,11 +229,12 @@ void write_specpol(const std::string &specpol_filename, const std::string &emiss const int proccount = get_proccount(); const int ioncount = get_nelements() * get_max_nions(); - for (int m = 0; m < MNUBINS; m++) { + assert_always(stokes_i->lower_freq.size() == stokes_i->delta_freq.size()); + for (size_t m = 0; m < stokes_i->lower_freq.size(); m++) { fprintf(specpol_file, "%g ", ((stokes_i->lower_freq[m] + (stokes_i->delta_freq[m] / 2)))); // Stokes I - for (int p = 0; p < globals::ntstep; p++) { + for (int p = 0; p < globals::ntimesteps; p++) { fprintf(specpol_file, "%g ", stokes_i->timesteps[p].flux[m]); if (do_emission_res) { @@ -273,7 +251,7 @@ void write_specpol(const std::string &specpol_filename, const std::string &emiss } // Stokes Q - for (int p = 0; p < globals::ntstep; p++) { + for (int p = 0; p < globals::ntimesteps; p++) { fprintf(specpol_file, "%g ", stokes_q->timesteps[p].flux[m]); if (do_emission_res) { @@ -290,7 +268,7 @@ void write_specpol(const std::string &specpol_filename, const std::string &emiss } // Stokes U - for (int p = 0; p < globals::ntstep; p++) { + for (int p = 0; p < globals::ntimesteps; p++) { fprintf(specpol_file, "%g ", stokes_u->timesteps[p].flux[m]); if (do_emission_res) { @@ -352,7 +330,7 @@ static auto columnindex_from_emissiontype(const int et) -> int { } static void add_to_spec(const struct packet *const pkt_ptr, const int current_abin, struct spec &spectra, - struct spec *stokes_i, struct spec *stokes_q, struct spec *stokes_u) + const struct spec *stokes_i, const struct spec *stokes_q, const struct spec *stokes_u) // Routine to add a packet to the outgoing spectrum. { // Need to (1) decide which time bin to put it in and (2) which frequency bin. @@ -370,8 +348,8 @@ static void add_to_spec(const struct packet *const pkt_ptr, const int current_ab const int nnu = static_cast((log(pkt_ptr->nu_rf) - log(nu_min)) / dlognu); assert_always(nnu < MNUBINS); - const double deltaE = pkt_ptr->e_rf / globals::time_step[nt].width / spectra.delta_freq[nnu] / 4.e12 / PI / PARSEC / - PARSEC / globals::nprocs * anglefactor; + const double deltaE = pkt_ptr->e_rf / globals::timesteps[nt].width / spectra.delta_freq[nnu] / 4.e12 / PI / PARSEC / + PARSEC / globals::nprocs_exspec * anglefactor; spectra.timesteps[nt].flux[nnu] += deltaE; @@ -428,8 +406,8 @@ static void add_to_spec(const struct packet *const pkt_ptr, const int current_ab const int nnu_abs = static_cast((log(pkt_ptr->absorptionfreq) - log(nu_min)) / dlognu); if (nnu_abs >= 0 && nnu_abs < MNUBINS) { const int ioncount = get_nelements() * get_max_nions(); - const double deltaE_absorption = pkt_ptr->e_rf / globals::time_step[nt].width / spectra.delta_freq[nnu_abs] / - 4.e12 / PI / PARSEC / PARSEC / globals::nprocs * anglefactor; + const double deltaE_absorption = pkt_ptr->e_rf / globals::timesteps[nt].width / spectra.delta_freq[nnu_abs] / + 4.e12 / PI / PARSEC / PARSEC / globals::nprocs_exspec * anglefactor; const int at = pkt_ptr->absorptiontype; if (at >= 0) { /// bb-emission @@ -472,8 +450,7 @@ static void add_to_spec(const struct packet *const pkt_ptr, const int current_ab void init_spectrum_trace() { if (TRACE_EMISSION_ABSORPTION_REGION_ON) { traceemission_totalenergy = 0.; - traceemissionabsorption = - static_cast(malloc(globals::nlines * sizeof(emissionabsorptioncontrib))); + traceemissionabsorption.resize(globals::nlines); traceabsorption_totalenergy = 0.; for (int i = 0; i < globals::nlines; i++) { traceemissionabsorption[i].energyemitted = 0.; @@ -491,120 +468,80 @@ void init_spectra(struct spec &spectra, const double nu_min, const double nu_max // step sizes first. assert_always(MNUBINS > 0); - + size_t mem_usage = 0; const double dlognu = (log(nu_max) - log(nu_min)) / MNUBINS; spectra.nu_min = nu_min; spectra.nu_max = nu_max; spectra.do_emission_res = do_emission_res; - assert_always(spectra.lower_freq.get() != nullptr); - assert_always(spectra.delta_freq.get() != nullptr); - for (int nnu = 0; nnu < MNUBINS; nnu++) { + const bool print_memusage = + (spectra.lower_freq.empty() || (do_emission_res && spectra.absorptionalltimesteps.empty())); + + spectra.lower_freq.resize(MNUBINS); + spectra.delta_freq.resize(spectra.lower_freq.size()); + for (size_t nnu = 0; nnu < spectra.lower_freq.size(); nnu++) { spectra.lower_freq[nnu] = exp(log(nu_min) + (nnu * (dlognu))); spectra.delta_freq[nnu] = exp(log(nu_min) + ((nnu + 1) * (dlognu))) - spectra.lower_freq[nnu]; } - assert_always(spectra.timesteps != nullptr); + spectra.do_emission_res = do_emission_res; // might be set true later by alloc_emissionabsorption_spectra - const int proccount = get_proccount(); - const int ioncount = get_nelements() * get_max_nions(); - for (int nts = 0; nts < globals::ntstep; nts++) { - assert_always(spectra.timesteps[nts].flux != nullptr); - for (int nnu = 0; nnu < MNUBINS; nnu++) { - spectra.timesteps[nts].flux[nnu] = 0.0; - } + spectra.timesteps.resize(globals::ntimesteps); + spectra.fluxalltimesteps.resize(globals::ntimesteps * MNUBINS); + std::ranges::fill(spectra.fluxalltimesteps, 0.0); - if (do_emission_res) { - assert_always(spectra.timesteps[nts].emission != nullptr); - assert_always(spectra.timesteps[nts].trueemission != nullptr); - for (int i = 0; i < MNUBINS * proccount; i++) { - spectra.timesteps[nts].emission[i] = 0; - spectra.timesteps[nts].trueemission[i] = 0; - } + mem_usage += globals::ntimesteps * sizeof(struct spec); + mem_usage += globals::ntimesteps * sizeof(struct timestepspec); + mem_usage += globals::ntimesteps * MNUBINS * sizeof(double); - assert_always(spectra.timesteps[nts].absorption != nullptr); - for (int i = 0; i < MNUBINS * ioncount; i++) { - spectra.timesteps[nts].absorption[i] = 0; - } - } + for (int nts = 0; nts < globals::ntimesteps; nts++) { + spectra.timesteps[nts].flux = &spectra.fluxalltimesteps[nts * MNUBINS]; } -} - -static void alloc_emissionabsorption_spectra(auto &spectra) { - size_t mem_usage = 0; - const int proccount = get_proccount(); - spectra->do_emission_res = true; - mem_usage += globals::ntstep * MNUBINS * get_nelements() * get_max_nions() * sizeof(double); - spectra->absorptionalltimesteps = - std::make_unique(globals::ntstep * MNUBINS * get_nelements() * get_max_nions()); - assert_always(spectra->absorptionalltimesteps != nullptr); - - mem_usage += 2 * globals::ntstep * MNUBINS * proccount * sizeof(double); - spectra->emissionalltimesteps = std::make_unique(globals::ntstep * MNUBINS * proccount); - assert_always(spectra->emissionalltimesteps != nullptr); - - spectra->trueemissionalltimesteps = std::make_unique(globals::ntstep * MNUBINS * proccount); - assert_always(spectra->trueemissionalltimesteps != nullptr); - - for (int nts = 0; nts < globals::ntstep; nts++) { - assert_always(spectra->timesteps[nts].absorption == nullptr); - assert_always(spectra->timesteps[nts].emission == nullptr); - assert_always(spectra->timesteps[nts].trueemission == nullptr); - - spectra->timesteps[nts].absorption = - &spectra->absorptionalltimesteps[nts * MNUBINS * get_nelements() * get_max_nions()]; - - spectra->timesteps[nts].emission = &spectra->emissionalltimesteps[nts * MNUBINS * proccount]; - - spectra->timesteps[nts].trueemission = &spectra->trueemissionalltimesteps[nts * MNUBINS * proccount]; - - assert_always(spectra->timesteps[nts].absorption != nullptr); - assert_always(spectra->timesteps[nts].emission != nullptr); - assert_always(spectra->timesteps[nts].trueemission != nullptr); - } - printout("[info] mem_usage: allocated set of emission/absorption spectra occupying total of %.3f MB (nnubins %d)\n", - mem_usage / 1024. / 1024., MNUBINS); -} - -auto alloc_spectra(const bool do_emission_res) -> std::unique_ptr { - size_t mem_usage = 0; - assert_always(globals::ntstep > 0); - // std::unique_ptr spectra(new struct spec); - auto spectra = std::make_unique(); - mem_usage += globals::ntstep * sizeof(struct spec); + if (do_emission_res) { + const int proccount = get_proccount(); - spectra->do_emission_res = false; // might be set true later by alloc_emissionabsorption_spectra - spectra->lower_freq = std::make_unique(MNUBINS); - spectra->delta_freq = std::make_unique(MNUBINS); + mem_usage += globals::ntimesteps * MNUBINS * get_nelements() * get_max_nions() * sizeof(double); + mem_usage += 2 * globals::ntimesteps * MNUBINS * proccount * sizeof(double); - spectra->timesteps = std::make_unique(globals::ntstep); - mem_usage += globals::ntstep * sizeof(struct timestepspec); + spectra.absorptionalltimesteps.resize(globals::ntimesteps * MNUBINS * get_nelements() * get_max_nions()); + spectra.emissionalltimesteps.resize(globals::ntimesteps * MNUBINS * proccount); + spectra.trueemissionalltimesteps.resize(globals::ntimesteps * MNUBINS * proccount); - spectra->fluxalltimesteps = std::make_unique(globals::ntstep * MNUBINS); - mem_usage += globals::ntstep * MNUBINS * sizeof(double); + std::ranges::fill(spectra.absorptionalltimesteps, 0.0); + std::ranges::fill(spectra.emissionalltimesteps, 0.0); + std::ranges::fill(spectra.trueemissionalltimesteps, 0.0); - assert_always(MNUBINS > 0); - for (int nts = 0; nts < globals::ntstep; nts++) { - spectra->timesteps[nts].flux = &spectra->fluxalltimesteps[nts * MNUBINS]; + for (size_t nts = 0; nts < spectra.timesteps.size(); nts++) { + spectra.timesteps[nts].absorption = + &spectra.absorptionalltimesteps[nts * MNUBINS * get_nelements() * get_max_nions()]; + spectra.timesteps[nts].emission = &spectra.emissionalltimesteps[nts * MNUBINS * proccount]; + spectra.timesteps[nts].trueemission = &spectra.trueemissionalltimesteps[nts * MNUBINS * proccount]; + } + if (print_memusage) { + printout("[info] mem_usage: set of emission/absorption spectra occupy %.3f MB (nnubins %d)\n", + mem_usage / 1024. / 1024., MNUBINS); + } - spectra->timesteps[nts].absorption = nullptr; - spectra->timesteps[nts].emission = nullptr; - spectra->timesteps[nts].trueemission = nullptr; - } + } else { + for (int nts = 0; nts < globals::ntimesteps; nts++) { + spectra.timesteps[nts].absorption = nullptr; + spectra.timesteps[nts].emission = nullptr; + spectra.timesteps[nts].trueemission = nullptr; + } - printout("[info] mem_usage: allocated set of spectra occupying total of %.3f MB (nnubins %d)\n", - mem_usage / 1024. / 1024., MNUBINS); + spectra.absorptionalltimesteps.clear(); + spectra.emissionalltimesteps.clear(); + spectra.trueemissionalltimesteps.clear(); - if (do_emission_res) { - alloc_emissionabsorption_spectra(spectra); + if (print_memusage) { + printout("[info] mem_usage: set of spectra occupy %.3f MB (nnubins %d)\n", mem_usage / 1024. / 1024., MNUBINS); + } } - - return spectra; } -void add_to_spec_res(const struct packet *const pkt_ptr, int current_abin, struct spec &spectra, struct spec *stokes_i, - struct spec *stokes_q, struct spec *stokes_u) +void add_to_spec_res(const struct packet *const pkt_ptr, int current_abin, struct spec &spectra, + const struct spec *stokes_i, const struct spec *stokes_q, const struct spec *stokes_u) // Routine to add a packet to the outgoing spectrum. { // Need to (1) decide which time bin to put it in and (2) which frequency bin. @@ -620,18 +557,18 @@ void add_to_spec_res(const struct packet *const pkt_ptr, int current_abin, struc } #ifdef MPI_ON -static void mpi_reduce_spectra(int my_rank, struct spec *spectra, int numtimesteps) { +static void mpi_reduce_spectra(int my_rank, struct spec &spectra, int numtimesteps) { for (int n = 0; n < numtimesteps; n++) { - MPI_Reduce(my_rank == 0 ? MPI_IN_PLACE : spectra->timesteps[n].flux, spectra->timesteps[n].flux, MNUBINS, - MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); + MPI_Reduce(my_rank == 0 ? MPI_IN_PLACE : spectra.timesteps[n].flux, spectra.timesteps[n].flux, MNUBINS, MPI_DOUBLE, + MPI_SUM, 0, MPI_COMM_WORLD); - if (spectra->do_emission_res) { + if (spectra.do_emission_res) { const int proccount = get_proccount(); - MPI_Reduce(my_rank == 0 ? MPI_IN_PLACE : spectra->timesteps[n].absorption, spectra->timesteps[n].absorption, + MPI_Reduce(my_rank == 0 ? MPI_IN_PLACE : spectra.timesteps[n].absorption, spectra.timesteps[n].absorption, MNUBINS * get_nelements() * get_max_nions(), MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); - MPI_Reduce(my_rank == 0 ? MPI_IN_PLACE : spectra->timesteps[n].emission, spectra->timesteps[n].emission, + MPI_Reduce(my_rank == 0 ? MPI_IN_PLACE : spectra.timesteps[n].emission, spectra.timesteps[n].emission, MNUBINS * proccount, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); - MPI_Reduce(my_rank == 0 ? MPI_IN_PLACE : spectra->timesteps[n].trueemission, spectra->timesteps[n].trueemission, + MPI_Reduce(my_rank == 0 ? MPI_IN_PLACE : spectra.timesteps[n].trueemission, spectra.timesteps[n].trueemission, MNUBINS * proccount, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); } } @@ -641,52 +578,43 @@ static void mpi_reduce_spectra(int my_rank, struct spec *spectra, int numtimeste void write_partial_lightcurve_spectra(int my_rank, int nts, struct packet *pkts) { const time_t time_func_start = time(nullptr); - std::vector rpkt_light_curve_lum(globals::ntstep, 0.); - std::vector rpkt_light_curve_lumcmf(globals::ntstep, 0.); - std::vector gamma_light_curve_lum(globals::ntstep, 0.); - std::vector gamma_light_curve_lumcmf(globals::ntstep, 0.); + std::vector rpkt_light_curve_lum(globals::ntimesteps, 0.); + std::vector rpkt_light_curve_lumcmf(globals::ntimesteps, 0.); + std::vector gamma_light_curve_lum(globals::ntimesteps, 0.); + std::vector gamma_light_curve_lumcmf(globals::ntimesteps, 0.); TRACE_EMISSION_ABSORPTION_REGION_ON = false; bool do_emission_res = WRITE_PARTIAL_EMISSIONABSORPTIONSPEC ? globals::do_emission_res : false; - if (rpkt_spectra == nullptr) { - rpkt_spectra = alloc_spectra(do_emission_res); - assert_always(rpkt_spectra != nullptr); - } - - struct spec *stokes_i = nullptr; - struct spec *stokes_q = nullptr; - struct spec *stokes_u = nullptr; - // the emission resolved spectra are slow to generate, so only allow making them for the final timestep or every n if (WRITE_PARTIAL_EMISSIONABSORPTIONSPEC && globals::do_emission_res) { - if ((nts >= globals::ftstep - 1) || (nts % 5 == 0)) { + if ((nts >= globals::timestep_finish - 1) || (nts % 5 == 0)) { do_emission_res = true; } } - init_spectra(*rpkt_spectra, NU_MIN_R, NU_MAX_R, do_emission_res); + init_spectra(rpkt_spectra, NU_MIN_R, NU_MAX_R, do_emission_res); for (int ii = 0; ii < globals::npkts; ii++) { if (pkts[ii].type == TYPE_ESCAPE) { const int abin = -1; // all angles if (pkts[ii].escape_type == TYPE_RPKT) { - add_to_lc_res(&pkts[ii], abin, rpkt_light_curve_lum.data(), rpkt_light_curve_lumcmf.data()); - add_to_spec_res(&pkts[ii], abin, *rpkt_spectra, stokes_i, stokes_q, stokes_u); + add_to_lc_res(&pkts[ii], abin, rpkt_light_curve_lum, rpkt_light_curve_lumcmf); + add_to_spec_res(&pkts[ii], abin, rpkt_spectra, nullptr, nullptr, nullptr); } else if (abin == -1 && pkts[ii].escape_type == TYPE_GAMMA) { - add_to_lc_res(&pkts[ii], abin, gamma_light_curve_lum.data(), gamma_light_curve_lumcmf.data()); + add_to_lc_res(&pkts[ii], abin, gamma_light_curve_lum, gamma_light_curve_lumcmf); } } } const int numtimesteps = nts + 1; // only produce spectra and light curves up to one past nts - assert_always(numtimesteps <= globals::ntstep); + assert_always(numtimesteps <= globals::ntimesteps); const time_t time_mpireduction_start = time(nullptr); #ifdef MPI_ON MPI_Barrier(MPI_COMM_WORLD); - mpi_reduce_spectra(my_rank, rpkt_spectra.get(), numtimesteps); + mpi_reduce_spectra(my_rank, rpkt_spectra, numtimesteps); MPI_Reduce(my_rank == 0 ? MPI_IN_PLACE : rpkt_light_curve_lum.data(), rpkt_light_curve_lum.data(), numtimesteps, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); MPI_Reduce(my_rank == 0 ? MPI_IN_PLACE : rpkt_light_curve_lumcmf.data(), rpkt_light_curve_lumcmf.data(), numtimesteps, @@ -700,10 +628,9 @@ void write_partial_lightcurve_spectra(int my_rank, int nts, struct packet *pkts) const time_t time_mpireduction_end = time(nullptr); if (my_rank == 0) { - write_light_curve("light_curve.out", -1, rpkt_light_curve_lum.data(), rpkt_light_curve_lumcmf.data(), numtimesteps); - write_light_curve("gamma_light_curve.out", -1, gamma_light_curve_lum.data(), gamma_light_curve_lumcmf.data(), - numtimesteps); - write_spectrum("spec.out", "emission.out", "emissiontrue.out", "absorption.out", *rpkt_spectra, numtimesteps); + write_light_curve("light_curve.out", -1, rpkt_light_curve_lum, rpkt_light_curve_lumcmf, numtimesteps); + write_light_curve("gamma_light_curve.out", -1, gamma_light_curve_lum, gamma_light_curve_lumcmf, numtimesteps); + write_spectrum("spec.out", "emission.out", "emissiontrue.out", "absorption.out", rpkt_spectra, numtimesteps); } #ifdef MPI_ON diff --git a/spectrum.h b/spectrum.h index 3164231d8..24a5a7f2f 100644 --- a/spectrum.h +++ b/spectrum.h @@ -3,6 +3,7 @@ #include #include +#include struct timestepspec { double *flux = nullptr; @@ -14,27 +15,27 @@ struct timestepspec { struct spec { double nu_min = -1.; double nu_max = -1.; - std::unique_ptr lower_freq = nullptr; - std::unique_ptr delta_freq = nullptr; - std::unique_ptr fluxalltimesteps = nullptr; - std::unique_ptr absorptionalltimesteps = nullptr; - std::unique_ptr emissionalltimesteps = nullptr; - std::unique_ptr trueemissionalltimesteps = nullptr; - std::unique_ptr timesteps = nullptr; - bool do_emission_res = true; + std::vector lower_freq; + std::vector delta_freq; + std::vector fluxalltimesteps; + std::vector absorptionalltimesteps; + std::vector emissionalltimesteps; + std::vector trueemissionalltimesteps; + std::vector timesteps; + bool do_emission_res = false; }; -void write_spectrum(const std::string &spec_filename, const char *emission_filename, const char *trueemission_filename, - const char *absorption_filename, const struct spec &spectra, int numtimesteps); +void write_spectrum(const std::string &spec_filename, const std::string &emission_filename, + const std::string &trueemission_filename, const std::string &absorption_filename, + const struct spec &spectra, int numtimesteps); void write_specpol(const std::string &specpol_filename, const std::string &emission_filename, - const std::string &absorption_filename, struct spec *stokes_i, struct spec *stokes_q, - struct spec *stokes_u); + const std::string &absorption_filename, const struct spec *stokes_i, const struct spec *stokes_q, + const struct spec *stokes_u); -void add_to_spec_res(const struct packet *pkt_ptr, int current_abin, struct spec &spectra, struct spec *stokes_i, - struct spec *stokes_q, struct spec *stokes_u); +void add_to_spec_res(const struct packet *const pkt_ptr, int current_abin, struct spec &spectra, + const struct spec *stokes_i, const struct spec *stokes_q, const struct spec *stokes_u); -std::unique_ptr alloc_spectra(bool do_emission_res); void init_spectra(struct spec &spectra, double nu_min, double nu_max, bool do_emission_res); void init_spectrum_trace(); void write_partial_lightcurve_spectra(int my_rank, int nts, struct packet *pkts); diff --git a/stats.cc b/stats.cc index 33f18eaa1..f991c087d 100644 --- a/stats.cc +++ b/stats.cc @@ -1,5 +1,8 @@ #include "stats.h" +#include +#include + #include "atomic.h" #include "globals.h" #include "grid.h" @@ -9,21 +12,19 @@ namespace stats { static double *ionstats = nullptr; -static int *eventstats = nullptr; +static std::array, COUNTER_COUNT> eventstats; void init() { if constexpr (TRACK_ION_STATS) { ionstats = static_cast(malloc(grid::get_npts_model() * get_includedions() * ION_STAT_COUNT * sizeof(double))); } - eventstats = static_cast(malloc(COUNTER_COUNT * sizeof(int))); } void cleanup() { if constexpr (TRACK_ION_STATS) { free(ionstats); } - free(eventstats); } void increment_ion_stats(const int modelgridindex, const int element, const int ion, enum ionstattypes ionstattype, @@ -145,7 +146,7 @@ void normalise_ion_estimators(const int mgi, const double deltat, const double d if (i < nstatcounters_ratecoeff) { // convert photon event counters into rate coefficients set_ion_stats(mgi, element, ion, static_cast(i), - ratedensity / ionstagepop(mgi, element, ion)); + ratedensity / get_nnion(mgi, element, ion)); } else { set_ion_stats(mgi, element, ion, static_cast(i), ratedensity); } @@ -157,7 +158,7 @@ void normalise_ion_estimators(const int mgi, const double deltat, const double d void increment(enum eventcounters i) { assert_testmodeonly(i >= 0); assert_testmodeonly(i < COUNTER_COUNT); - safeincrement(eventstats[i]); + eventstats[i]++; } void pkt_action_counters_reset() { @@ -175,7 +176,7 @@ auto get_counter(enum eventcounters i) -> int { } void pkt_action_counters_printout(const struct packet *const pkt, const int nts) { - long allpktinteractions = 0; + u_int64_t allpktinteractions = 0; for (int i = 0; i < globals::npkts; i++) { assert_always(pkt[i].interactions >= 0); allpktinteractions += pkt[i].interactions; @@ -183,10 +184,10 @@ void pkt_action_counters_printout(const struct packet *const pkt, const int nts) const double meaninteractions = static_cast(allpktinteractions) / globals::npkts; printout("mean number of interactions per packet = %g\n", meaninteractions); - const double deltat = globals::time_step[nts].width; + const double deltat = globals::timesteps[nts].width; double modelvolume = 0.; for (int mgi = 0; mgi < grid::get_npts_model(); mgi++) { - modelvolume += grid::get_modelcell_assocvolume_tmin(mgi) * pow(globals::time_step[nts].mid / globals::tmin, 3); + modelvolume += grid::get_modelcell_assocvolume_tmin(mgi) * pow(globals::timesteps[nts].mid / globals::tmin, 3); } /// Printout packet statistics diff --git a/stats.h b/stats.h index 9435cef34..2649be66c 100644 --- a/stats.h +++ b/stats.h @@ -12,7 +12,6 @@ enum ionstattypes { ION_RADRECOMB_MACROATOM = 0, ION_RADRECOMB_KPKT = 1, ION_RADRECOMB_ABSORBED = 2, - ION_RADRECOMB_ESCAPED = 3, ION_BOUNDBOUND_MACROATOM = 4, ION_BOUNDBOUND_ABSORBED = 5, ION_NTION = 6, diff --git a/tests/classicmode_inputfiles/abundances.txt b/tests/classicmode_1d_3dgrid_inputfiles/abundances.txt similarity index 100% rename from tests/classicmode_inputfiles/abundances.txt rename to tests/classicmode_1d_3dgrid_inputfiles/abundances.txt diff --git a/tests/classicmode_inputfiles/compositiondata.txt b/tests/classicmode_1d_3dgrid_inputfiles/compositiondata.txt similarity index 100% rename from tests/classicmode_inputfiles/compositiondata.txt rename to tests/classicmode_1d_3dgrid_inputfiles/compositiondata.txt diff --git a/tests/classicmode_inputfiles/input-newrun.txt b/tests/classicmode_1d_3dgrid_inputfiles/input-newrun.txt similarity index 92% rename from tests/classicmode_inputfiles/input-newrun.txt rename to tests/classicmode_1d_3dgrid_inputfiles/input-newrun.txt index f4145f264..b70982c5b 100644 --- a/tests/classicmode_inputfiles/input-newrun.txt +++ b/tests/classicmode_1d_3dgrid_inputfiles/input-newrun.txt @@ -1,6 +1,6 @@ 1281360349 # pre_zseed: specific random number seed if > 0 or random if negative -50 # globals::ntstep: number of timesteps -000 036 # itstep ftstep: number of start and end time step +50 # globals::ntimesteps: number of timesteps +000 036 # timestep_start timestep_finish: number of start and end time step 3 30 # tmin_days tmax_days: start and end times [day] 1.33 1.330000001 # nusyn_min_mev nusyn_max_mev: lowest and highest frequency to synthesise [MeV] 80 # nsyn_time: number of times for synthesis diff --git a/tests/classicmode_inputfiles/input-resume.txt b/tests/classicmode_1d_3dgrid_inputfiles/input-resume.txt similarity index 92% rename from tests/classicmode_inputfiles/input-resume.txt rename to tests/classicmode_1d_3dgrid_inputfiles/input-resume.txt index bc8a0edcb..538497ae2 100644 --- a/tests/classicmode_inputfiles/input-resume.txt +++ b/tests/classicmode_1d_3dgrid_inputfiles/input-resume.txt @@ -1,6 +1,6 @@ 1281360349 # pre_zseed: specific random number seed if > 0 or random if negative -50 # globals::ntstep: number of timesteps -035 050 # itstep ftstep: number of start and end time step +50 # globals::ntimesteps: number of timesteps +035 050 # timestep_start timestep_finish: number of start and end time step 3 30 # tmin_days tmax_days: start and end times [day] 1.33 1.330000001 # nusyn_min_mev nusyn_max_mev: lowest and highest frequency to synthesise [MeV] 80 # nsyn_time: number of times for synthesis diff --git a/tests/classicmode_inputfiles/model.txt b/tests/classicmode_1d_3dgrid_inputfiles/model.txt similarity index 100% rename from tests/classicmode_inputfiles/model.txt rename to tests/classicmode_1d_3dgrid_inputfiles/model.txt diff --git a/tests/classicmode_1d_3dgrid_inputfiles/results_md5_final.txt b/tests/classicmode_1d_3dgrid_inputfiles/results_md5_final.txt new file mode 100644 index 000000000..432d20e55 --- /dev/null +++ b/tests/classicmode_1d_3dgrid_inputfiles/results_md5_final.txt @@ -0,0 +1,25 @@ +43bf9f48a0f511482f5fab8a05d204d4 absorption.out +689de69d0631b260607f632cefa3a312 absorptionpol.out +c0604236aa7df99cda43e5c7bbe7b6f4 bflist.out +7c861e2528b3e7066bee6d1eb09b2623 deposition.out +635759cfc84035d2152ad72fe25a8089 emission.out +fe1d5ff2dc8076a20e087d8a880a57a5 emissionpol.out +03199910aa88c84f89b1bab3aab547e1 emissiontrue.out +e9a3293583a923eaf94d04f4b71bacc1 gamma_light_curve.out +3f823170e969aad8252d685a2284f70a gamma_spec.out +057b226c371f3819cba5e04bfea3d114 gammalinelist.out +20bddb22b6f084a7abc105c210366bfd grid.out +27e9af272dcd0b6a9bd03966e35195c7 light_curve.out +5740f40190d45653e5fce57ddf577dc8 linestat.out +c4e4e8d00846618f3931dc01cf52615f modelgridrankassignments.out +b5585182cae11527810cfb82072fb919 packets00_0000.out +3595e9d4484a55eb1d40d1f44fd168fc packets00_0001.out +e3e8093504b5f4ceb4b23924e750f0b2 spec.out +bbf9c836a1bbc64f7919d8c2dccb6b52 specpol.out +040c71f981716a2abf0467a82b1ac13c timesteps.out +08647501befa081004acc883edb7898a vpkt_grid_0-0.out +b2a6c81cfd8605508b89ed47f1f83be6 vpkt_grid_1-0.out +8d19f1a64dd5cb69869048df175a8a02 vspecpol_0-0.out +804848d2d65244f3c5d481db0384213b vspecpol_1-0.out +263568b30ce0c2633fbec2157aaa1114 job1/estimators_0000.out +b2ebf78e08410d7c7562d0d06120c95e job1/estimators_0001.out diff --git a/tests/classicmode_1d_3dgrid_inputfiles/results_md5_job0.txt b/tests/classicmode_1d_3dgrid_inputfiles/results_md5_job0.txt new file mode 100644 index 000000000..8e9004e13 --- /dev/null +++ b/tests/classicmode_1d_3dgrid_inputfiles/results_md5_job0.txt @@ -0,0 +1,21 @@ +fd071bf164378576c70bc25583f0eadb absorption.out +c0604236aa7df99cda43e5c7bbe7b6f4 bflist.out +776e733e780e8fb7509a5b3578bad22a deposition.out +f9368d553c9ce47d2a653fb8d7cd8840 emission.out +d1bfa2500e1516981f0bddf42c8a6038 emissiontrue.out +94f7bdd6bf7c8d2f30e0beb08280805c gamma_light_curve.out +057b226c371f3819cba5e04bfea3d114 gammalinelist.out +20bddb22b6f084a7abc105c210366bfd grid.out +5624f2243562637cd6d885e4b77e2867 light_curve.out +5740f40190d45653e5fce57ddf577dc8 linestat.out +c4e4e8d00846618f3931dc01cf52615f modelgridrankassignments.out +1d1e1bba1dc6890d01ec086506017bcf packets00_0000.out +13c47cc21b83945e9f0711328825ff42 packets00_0001.out +814474a12997e69688761d0836d3e98a spec.out +040c71f981716a2abf0467a82b1ac13c timesteps.out +99c590d59e35705e779c220134f7a33a vpkt_grid_0-0.out +35ce3462e5b9493bde385b8bad9ea954 vpkt_grid_1-0.out +2ed5cc4ea567b624eb8a4cb9137a2e01 vspecpol_0-0.out +01fd53e3ca382c4e2b0f5b588edbd9e5 vspecpol_1-0.out +2c67a882e73f240ecfeffa05f04d8c5f job0/estimators_0000.out +33ea538a70082b2a2ae43ae71569fc3e job0/estimators_0001.out diff --git a/tests/classicmode_inputfiles/syn_dir.txt b/tests/classicmode_1d_3dgrid_inputfiles/syn_dir.txt similarity index 100% rename from tests/classicmode_inputfiles/syn_dir.txt rename to tests/classicmode_1d_3dgrid_inputfiles/syn_dir.txt diff --git a/tests/classicmode_1d_3dgrid_inputfiles/vpkt.txt b/tests/classicmode_1d_3dgrid_inputfiles/vpkt.txt new file mode 100644 index 000000000..46343881e --- /dev/null +++ b/tests/classicmode_1d_3dgrid_inputfiles/vpkt.txt @@ -0,0 +1,14 @@ +2 +1 0 +0 0 +1 12 0 -1 1 2 6 8 14 16 20 26 27 28 +0 10 30 +1 1 3500 10000 +1 100 +10 +1 +11.5 21.5 +2 3500 6000 6400 7200 + + + diff --git a/tests/classicmode_3d_inputfiles/input-newrun.txt b/tests/classicmode_3d_inputfiles/input-newrun.txt index 8849e0e37..569806299 100644 --- a/tests/classicmode_3d_inputfiles/input-newrun.txt +++ b/tests/classicmode_3d_inputfiles/input-newrun.txt @@ -1,6 +1,6 @@ 1281360349 # pre_zseed: specific random number seed if > 0 or random if negative -30 # globals::ntstep: number of timesteps -000 011 # itstep ftstep: number of start and end time step +30 # globals::ntimesteps: number of timesteps +000 011 # timestep_start timestep_finish: number of start and end time step 3 8 # tmin_days tmax_days: start and end times [day] 1.33 1.330000001 # nusyn_min_mev nusyn_max_mev: lowest and highest frequency to synthesise [MeV] 80 # nsyn_time: number of times for synthesis diff --git a/tests/classicmode_3d_inputfiles/input-resume.txt b/tests/classicmode_3d_inputfiles/input-resume.txt index 33ca4a2fb..d92fa54bb 100644 --- a/tests/classicmode_3d_inputfiles/input-resume.txt +++ b/tests/classicmode_3d_inputfiles/input-resume.txt @@ -1,6 +1,6 @@ 1281360349 # pre_zseed: specific random number seed if > 0 or random if negative -30 # globals::ntstep: number of timesteps -010 030 # itstep ftstep: number of start and end time step +30 # globals::ntimesteps: number of timesteps +010 030 # timestep_start timestep_finish: number of start and end time step 3 8 # tmin_days tmax_days: start and end times [day] 1.33 1.330000001 # nusyn_min_mev nusyn_max_mev: lowest and highest frequency to synthesise [MeV] 80 # nsyn_time: number of times for synthesis diff --git a/tests/classicmode_3d_inputfiles/results_md5_final.txt b/tests/classicmode_3d_inputfiles/results_md5_final.txt index ce0f19b82..4fc5b78cb 100644 --- a/tests/classicmode_3d_inputfiles/results_md5_final.txt +++ b/tests/classicmode_3d_inputfiles/results_md5_final.txt @@ -1,524 +1,524 @@ -7e563d43a4bbeb413b23bddc499c12b4 absorption.out -e86f731e121b8c635b4966478b15f138 absorption_res_00.out -892b57a14835f887e9efa013c1f527ba absorption_res_01.out -35e16bcb5ed2102b92673f47e2d1676a absorption_res_02.out -6d021f2c8576a3fdf69c4e0a9236bcb6 absorption_res_03.out -8e1b546f060dae2cde17602e3eb83711 absorption_res_04.out -561eec609c2a76cb94dba0c9bb87a6b5 absorption_res_05.out -177113cb4953ae8698402eb2c8c9c80d absorption_res_06.out -08a279bad1bd5a09e9624795ae50e8d1 absorption_res_07.out -95415868a755988d2eec9fb9156871ba absorption_res_08.out -99c54f416b3f5f1c9fd2c03300fd5fab absorption_res_09.out -56f1a0626c89c895424b64e8a6ef1626 absorption_res_10.out -b37f59d411e21206a0c2822669777373 absorption_res_11.out -303659b22c8f93e843c0ed3526b34f10 absorption_res_12.out -4fa10c58874af347cdd09e30d6592ca1 absorption_res_13.out -e8c232b89ab5adef40091f51db912dc9 absorption_res_14.out -83d274b3198378dfb23fb192fec0c766 absorption_res_15.out -d9d2e561e82710ef6d973c5bf3d45b44 absorption_res_16.out -29274e3e32e3a0f6c45f51c84bb5d9c8 absorption_res_17.out -eff917c10b1dc1e903f71a28f51c337e absorption_res_18.out -03dbd3d295b1a4ee2cc55e099ec2e7e5 absorption_res_19.out -d9cbb6d2a7769db569a18a5502ad2be7 absorption_res_20.out -db1bcf91449d49a21ec4546a69d90753 absorption_res_21.out -fdb9f870b4d3b89a81179346ea6882a3 absorption_res_22.out -29c2c57902ed1f4899d9cf2b98b2a18d absorption_res_23.out -7c882566cde067addb588edd87f0cc63 absorption_res_24.out -78fbb89e66f0fd491be7e1cbf598d304 absorption_res_25.out -ed606ce0f478f3e0d46fa48c6ab87ce2 absorption_res_26.out -432291167e8159447395f3264ff87cd3 absorption_res_27.out -fb88e7434ce9442634c2157b71c692e6 absorption_res_28.out -68a09199cb2f30e503bd7747005f692f absorption_res_29.out -7b8508e20b5a7e867b05191c228e3f35 absorption_res_30.out -7e63abec8637f9e7100e453682fd631d absorption_res_31.out -766bfbe154d1ee219a98e99e304b1cce absorption_res_32.out -51e072517cee33924c7e156d814acd49 absorption_res_33.out -9179b51b6662ac53bd42c46debb4e16b absorption_res_34.out -99819734d583f74140f74c7a35459190 absorption_res_35.out -35521e46cbca3bc62e89a580572b2973 absorption_res_36.out -4a604f072a370d0ff2a6af4996e73acb absorption_res_37.out -483f593ecfe1b22c6c69ca381a57fea1 absorption_res_38.out -200f40cc531c0fa5cb321c8ae0d75945 absorption_res_39.out -b580805d982bf7f7e2723b9721670fb2 absorption_res_40.out -fe35dc839087d60ca3a2c7b9d3b62d0b absorption_res_41.out -6a279b33aeb15e37be8ac28cd4fa65cc absorption_res_42.out -812ed9987690b98a3a73e298820064af absorption_res_43.out -f02886a5c01711a3565db82e990bf741 absorption_res_44.out -3717312b9b97f6b4979241527dc115ac absorption_res_45.out -0269b6938f16caaf98c108d22d7dee0c absorption_res_46.out -074843258fab2641ce2a15b3f29c8bde absorption_res_47.out -9e6c98ec91a1ee6cbe01e5560aee2df7 absorption_res_48.out -a969ecf9d64b524a38df9e5d1662f5aa absorption_res_49.out -dfda60ded5436fb62b00466d168f59c5 absorption_res_50.out -b28dda54ecf6c896134a09c6f7b235f7 absorption_res_51.out -3ca30e9a76d87f09584a8f5355382e4d absorption_res_52.out -83b955a53a6ba636009c421cba754da7 absorption_res_53.out -ba2f7fc71ce3997781eb8cf58d3937b5 absorption_res_54.out -4e78f8ffe442f824f26c5f9a07e87b7b absorption_res_55.out -0d7b1a051727d9fbf387260275311587 absorption_res_56.out -33c89514bd5b64d19470e673df6594bc absorption_res_57.out -5d0b4c68ae0c4aacc810f219757c38c0 absorption_res_58.out -bcab9af6ee00102662ae15c864b0e6b3 absorption_res_59.out -e302a50022f16762ca5f967c3d94e396 absorption_res_60.out -a42bbb9b0b9f2e10171f7c0554301cca absorption_res_61.out -2436dfdbe05e45f5bd424ef858354522 absorption_res_62.out -88306f7cd86bbacea7cd52a661ad2687 absorption_res_63.out -69d94be33c39e0025a678fafe23c557d absorption_res_64.out -8104fbdac589d6f54db533976c20a477 absorption_res_65.out -ed161ceae7971b4c1127a4959e11a0c9 absorption_res_66.out -889e3821a08e7dbbfcf0799d8a5b2253 absorption_res_67.out -63390cc856f1fa836896b45fb4d29eb6 absorption_res_68.out -f3150725ad30171ad0dd508e902cabd2 absorption_res_69.out -fe6050baf49db9745c0bbba2216936b2 absorption_res_70.out -ef75731d73a2d2c495aef3be9249c652 absorption_res_71.out -e4487717dadda8e6987002bf05c192a2 absorption_res_72.out -a523cb31b187b1ce9bfc895421d028ad absorption_res_73.out -13a4ebc8f8482257f38826757e0776c1 absorption_res_74.out -46bd77c9964f90d420703cbd0c9a8dee absorption_res_75.out -63c7a235863812693056ebb42f9f9337 absorption_res_76.out -83c56f2d7a10a6c0ec9c82b34cc7d163 absorption_res_77.out -7568d4135cf415cfbfb7df8c3bbac72e absorption_res_78.out -86930423049d4f9c54ab9d1f5de941c0 absorption_res_79.out -f6b3efa66677b360c07412e2903f9a99 absorption_res_80.out -304c8180cdd3a2d248501f746f0d0d09 absorption_res_81.out -64b465d465331e2b6cbe3d30c50f3a69 absorption_res_82.out -b777d09a6161e0d9a50b8285d6bf59a7 absorption_res_83.out -39546187619c8043155b13492a0609eb absorption_res_84.out -52997511ba7f651ba0d05a2794c687a3 absorption_res_85.out -9152d79771b698464e75d711886766e7 absorption_res_86.out -feb414c724d4f3bebe911d1ca43d69e8 absorption_res_87.out -8170606383c15034f244cd1fe6721615 absorption_res_88.out -700c1c67fe36b675130cb58f819ac7f5 absorption_res_89.out -d7703757d078ab4b5934cd1e4de16beb absorption_res_90.out -cdfba32cfacb259dbd685220f63e3bef absorption_res_91.out -7e39bb3bf83665b9503b6ba98ef1acc0 absorption_res_92.out -bd8e5e8104cf64a0deae6612ddbc4dbb absorption_res_93.out -3921975d5cb9abc58cdd8f9e8bd994a5 absorption_res_94.out -4c242dd2c8944d8011079dfa7faf9760 absorption_res_95.out -48d6b129ffe4e13dd2bcb7df1b60fe82 absorption_res_96.out -c1b836858994ab496b9d60eeb05cbc75 absorption_res_97.out -4f43bd8cb2f7efa6c6452a602b7f8a15 absorption_res_98.out -d0027cbb335c4f1af8649fb6f2f89532 absorption_res_99.out -7c8bf09ed9824a8e615cbfe0efa0f5ad absorptionpol.out -63b547538521f044b0b1ed12d1255850 absorptionpol_res_00.out -d01eba1b7d7f0ce0317a45f2ec49cd38 absorptionpol_res_01.out -c398f0493cbdc4c5d63b0a67848590a1 absorptionpol_res_02.out -14c9b36d6da9a1ecc0c8f59bca9d44ca absorptionpol_res_03.out -6f8653ce7f820a195bb3373cab2bc26b absorptionpol_res_04.out -7190552244e2ded2e44e1d2692bf2ea7 absorptionpol_res_05.out -0d5beb0df2501c755e6ae217e24e65d2 absorptionpol_res_06.out -3c9e3e0722cb43211a784d8ad6b798bf absorptionpol_res_07.out -1b2a058a6183e0a2052618b21a7cf0c5 absorptionpol_res_08.out -2ddf33f51d6a3104e39d8cf891ed4f5d absorptionpol_res_09.out -55c0ec8f94eec62e25bf95897a0bca89 absorptionpol_res_10.out -86b8dc2513ed8bd17b3d2230b759b09d absorptionpol_res_11.out -c098f08614fda4492baad0d5f837695c absorptionpol_res_12.out -948a9d0ddf9cfc20c59f8fc31cd20304 absorptionpol_res_13.out -4c1cbd65c409ecb158caab99c613b483 absorptionpol_res_14.out -81f6b39e6e038b649df8a10d2cf9b047 absorptionpol_res_15.out -47d42131f047a0830dc968650f596b00 absorptionpol_res_16.out -94570db237788407340fa12b89e8553b absorptionpol_res_17.out -3300488702677331fe2bf2dbeeb2eb9c absorptionpol_res_18.out -e9ce120113974e7f5224304bdfd6501a absorptionpol_res_19.out -af0133a1ac06754134be54bf3f17782b absorptionpol_res_20.out -0d1999436738947b27c971d260339b18 absorptionpol_res_21.out -f4633105a031a37924fc0a77826ae4ea absorptionpol_res_22.out -bc09445389d2c4ec955f4afb4dd010d2 absorptionpol_res_23.out -56237d9730f078684df91c558dfa215e absorptionpol_res_24.out -2ae4883a382162fc2900b7e51bfc6c7f absorptionpol_res_25.out -9c947857b9e79e18d26a7313d103b2dc absorptionpol_res_26.out -7be3a95e7d20e35dfedd140d6af7b1f0 absorptionpol_res_27.out -b7388781823985efe13821d2d883984e absorptionpol_res_28.out -1dd58cbbeaf83188e0f47ed7e1f16c2a absorptionpol_res_29.out -2de6a3de1c79a011e3772146524a6c53 absorptionpol_res_30.out -4f8a5cc6380a2371e62eddd338bfcd87 absorptionpol_res_31.out -4b5f3f2a517a64a8372af39f5a3f95a6 absorptionpol_res_32.out -39ae2c7a5bc5b0289e58c630f933273f absorptionpol_res_33.out -1da50b3fb27a4c0e9cb72d8e58fa522d absorptionpol_res_34.out -7bd58b4f8f0d39027ab9bd4dae17d196 absorptionpol_res_35.out -3ca18ac75a42ad033e20ba9ccb8550aa absorptionpol_res_36.out -a0c224c6090c8d670b635246c8f9030c absorptionpol_res_37.out -b19d270fc00382a49cc1e2560cc206ba absorptionpol_res_38.out -b08fec8d8319e6ceeaa5527f14fa9da3 absorptionpol_res_39.out -d792eed8b4866962656c858f88719cca absorptionpol_res_40.out -890336d5f5629c5075eba31b06233804 absorptionpol_res_41.out -22e8c1b9a6da5cb13cd74c91039d4511 absorptionpol_res_42.out -110f5c381cc56c9b682899b7853a3fe7 absorptionpol_res_43.out -9b6331679aa3df7293bd0892e9fbcced absorptionpol_res_44.out -970ad3f2ab426cae6c26fdb7d0a0dc11 absorptionpol_res_45.out -2406fa083a5882d8fbb2984d8139eed4 absorptionpol_res_46.out -c72076d4e90777331cb01bb8603e1bc2 absorptionpol_res_47.out -1a9f74fb2f60b44077ef0a0b77462528 absorptionpol_res_48.out -af8ca8c45249ec75f604a1d0ca7c8b76 absorptionpol_res_49.out -6e1fd5534eff933747c0430ccee91677 absorptionpol_res_50.out -05c64bf15480c80d67c3a07bcefd2369 absorptionpol_res_51.out -918814ec949ac27278196a0a788dd7c5 absorptionpol_res_52.out -c0f06578c13fe810d355ebe727240ea7 absorptionpol_res_53.out -d68f82434fa671dba7e88a3081e31d1b absorptionpol_res_54.out -88f076a2c81b1af0abd8c96712c4ebe2 absorptionpol_res_55.out -4d361b3f2623c0dbe4acaa9bfb71639b absorptionpol_res_56.out -a74d509826e3b5ea764e88538df5573f absorptionpol_res_57.out -1d6011984e38ba210d032ac29833d811 absorptionpol_res_58.out -a804a35e0886196a3205f1bfc5222598 absorptionpol_res_59.out -8c0a1917b76b8d3e9e15b27f9f1b1058 absorptionpol_res_60.out -999e4fa1c0873654f554c33c91b636c8 absorptionpol_res_61.out -c09b5896bbdb1271abffdea3860d072a absorptionpol_res_62.out -f38f5b412846da3738f03b7e8c77c358 absorptionpol_res_63.out -bb0717bbfce7cb64a812a57519cc6802 absorptionpol_res_64.out -87ca7cd77788c0ef9c4f291210867e83 absorptionpol_res_65.out -6171719e0add351f13b74315525e8d85 absorptionpol_res_66.out -147008c3c70f6794323293b5937b9093 absorptionpol_res_67.out -86913336f24b22aa8474ce5e0b3e65dc absorptionpol_res_68.out -3c9759b4497bddbb4b4ea51ebac60e6e absorptionpol_res_69.out -bfe120e8703376067d10643460f3f2fd absorptionpol_res_70.out -8a008fa3c44c239aae1f3036ccc1d5d5 absorptionpol_res_71.out -7ef2490895355a64e342b159aa62441a absorptionpol_res_72.out -f840f970e8d983eefb82a0602e441afc absorptionpol_res_73.out -5aab7de08ab6e5d6ab4297943a6d0249 absorptionpol_res_74.out -78304ae9636f4db5bf5225f1dba1891f absorptionpol_res_75.out -130f105f73774980d92ffe261c6aa1be absorptionpol_res_76.out -c1f6627ef0cb0e87ca3fc56a500d5526 absorptionpol_res_77.out -2eb6f54a796aab0bae4bb2496f5c62af absorptionpol_res_78.out -71a4d4e5b57e8b38ffe38f72ed697fd6 absorptionpol_res_79.out -6b376df12683e0e1ea819b81f0bb27fa absorptionpol_res_80.out -ccc5ea11c5a6824b09160e3731bde843 absorptionpol_res_81.out -c6890555ec301a03b11bcef6612aa91a absorptionpol_res_82.out -dd65fb19d61a06af236d55f8e225833e absorptionpol_res_83.out -fe2a4f8d5822656f0ce7089f2e6f1bb9 absorptionpol_res_84.out -ba08df401ecbdae9ac0bba28824493b0 absorptionpol_res_85.out -fd782f9bb8ee167b862ca847947486e6 absorptionpol_res_86.out -6920d2db75540a0a220f2212ce9e83a9 absorptionpol_res_87.out -26c64bcc9936447d994c53812c7ac613 absorptionpol_res_88.out -782255cde161074add33b900220b3440 absorptionpol_res_89.out -d9f65855e48177e9bbee78eee98cca4f absorptionpol_res_90.out -3fc1b1b5298d164f2645d960bd7fbae5 absorptionpol_res_91.out -2e12d18ea0c874bb1f6233a41429c19f absorptionpol_res_92.out -f10a91afb90ee363cf372c063e311f05 absorptionpol_res_93.out -575d6b42751763427ad997beaa734cbc absorptionpol_res_94.out -8c6cc47fdfe54727c4e313ff7194a689 absorptionpol_res_95.out -216c73404d088fc3bba7ea5f05156f25 absorptionpol_res_96.out -17ca87e194b86a7fe06010ddafc21fc1 absorptionpol_res_97.out -1e177cf4dea22aac872022ce521efec3 absorptionpol_res_98.out -209169a97813cb47f385218a619e7660 absorptionpol_res_99.out +af66a263b044c4166338608b98933ed0 absorption.out +d06fea586b692072daed1c8c4ab321a6 absorption_res_00.out +2f5435323fc0bdd6fe16b3e21592b2d7 absorption_res_01.out +9a56621395226f6d02bf5e73cf7f0bf7 absorption_res_02.out +e9cb980a30a2b6b2498ef3543c6cbbd7 absorption_res_03.out +619180ab91f262d9db621e3c3d2db12f absorption_res_04.out +43c28f5ab0df7b610ea06a3e632cbfa6 absorption_res_05.out +0e3282c5b03e29f462be2ae84775174d absorption_res_06.out +ac810093dd51adc189e6dbb293a05da3 absorption_res_07.out +27995ce183189f8226022d0465dc6fe9 absorption_res_08.out +99ab488db1912773f7b47ced030d252b absorption_res_09.out +e8aeaa225ff3b4b4de143c5840cc05a3 absorption_res_10.out +4f4f1804ad70aeb73b5f7d6cca969f02 absorption_res_11.out +2bc95e00f720c7382d22113da6fdb07d absorption_res_12.out +f0717b34b6f33d5eae5772e13fe65d85 absorption_res_13.out +589c4260c892b82b03a438ac018c5b35 absorption_res_14.out +1e48f727baabc35dbe40d02a702d31c1 absorption_res_15.out +b11b4c704c4f062b5f4bf7c0e461e4a3 absorption_res_16.out +52444caad2509a681c38a412d283f7e4 absorption_res_17.out +5f683a0c4d53cfc8b292c6983ae4d858 absorption_res_18.out +0c58ea6ff912b64a3bf65309311a250f absorption_res_19.out +d3df33e632bb0e6029b1729aa1f7e4fe absorption_res_20.out +f57067255bf65ca01e4a7c989a32e740 absorption_res_21.out +d1a805a38768062111d588d65c9f3792 absorption_res_22.out +5ed5720f8d024b491fd7c71f68dad2f2 absorption_res_23.out +133523a18df44b21aed0ef133518a127 absorption_res_24.out +bb6bcdd367f5d7aa9b54fea9ef2a0fb2 absorption_res_25.out +0ad97df0b2d163bc51746c916fb4820a absorption_res_26.out +a9465bcc39a29be9808853cb383c90c1 absorption_res_27.out +078ee3acd411ab6d909669ffc66c76e6 absorption_res_28.out +b65ab3e2df3ce02ecc9e8b5f6b916376 absorption_res_29.out +c430775ebfd2bae76ce26a15dd4c9e3f absorption_res_30.out +8dcb8523569d01bb8e5e4cc41a1a650e absorption_res_31.out +3803355524dd1418b8c66fc332196794 absorption_res_32.out +7e6ae48bf7c3f9b4c85a839cd4ddc0b5 absorption_res_33.out +468523034147eca758d02a68f1748303 absorption_res_34.out +313887fa364a72b8fc926578f4b05680 absorption_res_35.out +9fefba1537fa2747b0ca3620925f9dea absorption_res_36.out +80171bc2fc6dcf492d46bc3724aec0af absorption_res_37.out +965135406b249fd89432905372b9f5fb absorption_res_38.out +10d89e1ba8a96055f53eb3475cb7a6d9 absorption_res_39.out +3defb5369efd915fe5898ec87ef57e7f absorption_res_40.out +abb71f9ee0e1a96acff0ee9804de80a7 absorption_res_41.out +63ba34fa115faf76086226733171be41 absorption_res_42.out +8f8553df2f45f278d1459b98a21fc219 absorption_res_43.out +d1b671f2cc450532c1bf3a9e576073dd absorption_res_44.out +6cf78f0b9bd8b2a1e7ca0101ad9076a8 absorption_res_45.out +b059821cc166d52420276992e11e1b8b absorption_res_46.out +cd6ff853cb0de22ab9988d310eb5db75 absorption_res_47.out +ca789515db06dc4775c3898509a85e7b absorption_res_48.out +a36353a3954f5261b60fe9d0bcd7ed76 absorption_res_49.out +ffcbfc7a2c9b9545107665b2f2c40d3a absorption_res_50.out +81c52db5c5336635242d0d63cdea9294 absorption_res_51.out +6cf99d2ca390412ffffa6c162303656b absorption_res_52.out +22a7dedfd27b267dc8c2b06591790d10 absorption_res_53.out +b4ca43ca8bfea7a1fa305a284d55fe9f absorption_res_54.out +0f7c6bbd2ea2fae5e3cb5eaff4801166 absorption_res_55.out +7f2f707b8da24d8a03023ae77859ebf7 absorption_res_56.out +0a416f3691a8dbae6617e395a71b8939 absorption_res_57.out +e6a021b7eedea2f746e4a92b345bdd44 absorption_res_58.out +2cd47a787274e56b34df4f793d6ec64a absorption_res_59.out +c208559ba07bff4387ebc9a78da780ad absorption_res_60.out +0423888bf260a3d5c5c1b2a0affbe136 absorption_res_61.out +60ad0a4ddba36a60d748cfffa09ab770 absorption_res_62.out +3e348f48f9c2722ea8ccd3b36f0b4b2e absorption_res_63.out +98f43ccd2584d9e878ddb79e9e039ee8 absorption_res_64.out +add983c9980bdc89d020124495f07ce6 absorption_res_65.out +ea911bce3f94ea44048e1a370aaadf04 absorption_res_66.out +9a0d728386c4f9872fe5eef4040ad52e absorption_res_67.out +e238f278a5f24fcb0de7ac368a469c31 absorption_res_68.out +bbd276d4555ef24d5663f86d465eb8b2 absorption_res_69.out +d2ac757bd34fad015309ae0db278cb7d absorption_res_70.out +13b831182086c6e989202dde8126f167 absorption_res_71.out +f824221b87585dcbd2966c92fb3b4e38 absorption_res_72.out +7a66c4baa51832202c1623dbdf261bb4 absorption_res_73.out +9393ce8e5456b9086db7e4009221af6b absorption_res_74.out +a84a404949e3d8308e4d71a34870e142 absorption_res_75.out +81d5d62924bc01d4a2fcfa4613184b35 absorption_res_76.out +63ec3466e8255bb346021c60290e2211 absorption_res_77.out +96684492c67546816e811d856b62f7c1 absorption_res_78.out +7644214532a2b3e540dc49559d0a7ec9 absorption_res_79.out +35dbe01553533e1888a8eb0d40c37a96 absorption_res_80.out +72201c637dced72d0d6197206cd9dd34 absorption_res_81.out +9650767dec673cde391dcb525ef3495a absorption_res_82.out +8d5f59032ce377175982d35058d571f1 absorption_res_83.out +767ac83af929fe103f9fafb2d3074f19 absorption_res_84.out +c35628b306c6e132f2420b24e9833360 absorption_res_85.out +e303e129003638423d7b36ea5935e48e absorption_res_86.out +16290ff89efe890a64c02bd06c262af5 absorption_res_87.out +010bcdef6a90211800e3170d8d3b86fc absorption_res_88.out +045dbcfa9db8715d4395a2af30fc4d0a absorption_res_89.out +7e00e242493f2a00535b579ee69317d3 absorption_res_90.out +c6b4987bf0c38509ba99b2831d27e991 absorption_res_91.out +eaae51ebf9e829951da914095de7e243 absorption_res_92.out +17e05f62447fadbe05daf8850f3a302d absorption_res_93.out +16383e098a9034939b4a27ef79e52fb9 absorption_res_94.out +0b3efb880cfc80acfea4a1d71c3e9525 absorption_res_95.out +ac00a8d646daa4013159b3f267a556ef absorption_res_96.out +76119a9fc25ef92fc19f22fbd30befb3 absorption_res_97.out +eb72ee21d547641353f772263fe0e1df absorption_res_98.out +03348dd42d19a20bdc2ca7551cfb4191 absorption_res_99.out +2879fc84a512031c54f015d6a1952905 absorptionpol.out +d6efdae466e6c1a1d4444b38a2f78640 absorptionpol_res_00.out +3262598d5c6100198ee1cdafdbd1a316 absorptionpol_res_01.out +df2e7b3895aab56126db444bb5f64788 absorptionpol_res_02.out +8bd42a5f34376095064803dfd96e6713 absorptionpol_res_03.out +76f274aacf2d555f571bbef38bc4f7ed absorptionpol_res_04.out +95e81164e75f35e153773d7fe26f37d6 absorptionpol_res_05.out +b3d0f777df219548b0cc273a785322d2 absorptionpol_res_06.out +b0b10fea6c9a86574076a296c6b0e1fe absorptionpol_res_07.out +dbb8124243b26c146a366ceaf12e3747 absorptionpol_res_08.out +3c04109c9f61fea1bacc99495a5b6ae8 absorptionpol_res_09.out +1f89c06b40fb7b9e030c545e019a6307 absorptionpol_res_10.out +8982b3cfe52e559f0ab4ff7e3099209a absorptionpol_res_11.out +1f3519821de10e6154ee8c93930e0eca absorptionpol_res_12.out +1e29e36ab09dd3fbdd29ec29053b4f33 absorptionpol_res_13.out +116869aedf224cdc50111cc39fb8ac86 absorptionpol_res_14.out +5035c423e6b18ecf35ce3b334bffeab0 absorptionpol_res_15.out +bde87a6feda3513107ae51af53c94959 absorptionpol_res_16.out +a9dab3fb91a77c4c32bb136f434ee5b6 absorptionpol_res_17.out +924de250bde26eaa8bd35ed3bad5c2c6 absorptionpol_res_18.out +0322cfb73f85d72b0e3329c171270b00 absorptionpol_res_19.out +a05a6ce859f0178e14c5ea9c489f9c25 absorptionpol_res_20.out +c8d1e5adde9374adb0ebe1ea6ca67b65 absorptionpol_res_21.out +f777635df909e31ce1ba579377d1b993 absorptionpol_res_22.out +7105dac9117a3a5b5a09e24581999bf8 absorptionpol_res_23.out +9eb9a14b9a4fd15ba2551f1b406f9859 absorptionpol_res_24.out +be61afa97eec47797c4c597548712af1 absorptionpol_res_25.out +4a8202eb8927616eb2594fc2c6f3dff3 absorptionpol_res_26.out +bf11ce0c2dbc097caf6da99ccb6368f2 absorptionpol_res_27.out +8c9234d6316ac6c19cbfb664a7ab884f absorptionpol_res_28.out +03e397312d2783aeee79ae26ca5426d1 absorptionpol_res_29.out +abfdc97782dd65ef11e7dfcc6daf781a absorptionpol_res_30.out +55887a9b9d535de1a5f65e902716d980 absorptionpol_res_31.out +e81c53fef4fc89957bc8fb42f0746bfe absorptionpol_res_32.out +4c0e6d4339f14f8c3842c5348e9131ee absorptionpol_res_33.out +4a6b4cad9820e85ee49bea305f40179a absorptionpol_res_34.out +686787673c522afcd47470672b880b5f absorptionpol_res_35.out +e9b7b07239753882998e7ceab140dc83 absorptionpol_res_36.out +17bba06533a69f90266722af5e70e477 absorptionpol_res_37.out +ddd24e15c230f5a842047fb34f8ebc36 absorptionpol_res_38.out +3bb82370f426f370a91476e6680839aa absorptionpol_res_39.out +dab34ba9737844fda78b37c31c8e441d absorptionpol_res_40.out +39891e18a8dfeef3d33e98261ac8d387 absorptionpol_res_41.out +e214d4dc0936cd98bca4007514c7fcc1 absorptionpol_res_42.out +032250b07c92204293331b13b9f97dde absorptionpol_res_43.out +911fb1336059ccba60baf0afcc38b915 absorptionpol_res_44.out +f46de11a3e5eb3c617cfe6a65b6acee4 absorptionpol_res_45.out +f8cf3feee810da14f08783e3c3b8a287 absorptionpol_res_46.out +393d62772cfb487f6e4b063c6853ce45 absorptionpol_res_47.out +0e0f270c8659b30b064391cb03a93979 absorptionpol_res_48.out +b5cc7f21ea87cf79519ce96a9fb691b4 absorptionpol_res_49.out +aaf86213fa7b0de529dbab848099b7c8 absorptionpol_res_50.out +7ef395b87d405d41e514f423dce581aa absorptionpol_res_51.out +0821cfd63f08fb8bc0b4d3982babf2ec absorptionpol_res_52.out +9021ab084e1c7f2df7c52456279e3b6c absorptionpol_res_53.out +a55ca947bb9b98519bc00fcd9e53a429 absorptionpol_res_54.out +74dd4c2ec0a7bab8f77cdf83feaf04c4 absorptionpol_res_55.out +e1936ab63397702566e55671522cf13e absorptionpol_res_56.out +491e254893a9690a7f32dccd06a1bf31 absorptionpol_res_57.out +66dcf5ea41a03f278bf7cdcf1f7d3367 absorptionpol_res_58.out +92c25fe91c5c70d72c2c20009867c4ff absorptionpol_res_59.out +5337d1947f3d31760ec07f509c938727 absorptionpol_res_60.out +36062ec7d87eec6618a42a73ea6afbc8 absorptionpol_res_61.out +787c25dc5faff56a0037d18a74827ae6 absorptionpol_res_62.out +6f6fa4626194bee6b50f0cd1bf7e0e09 absorptionpol_res_63.out +19b54f227cd231f7d49246c3407aba1c absorptionpol_res_64.out +d277917a0d86c5613ae61bf620e78416 absorptionpol_res_65.out +5549291a984f72fa3a9de1e1e659d690 absorptionpol_res_66.out +08e98f963ec1365de9eb7168868b3bde absorptionpol_res_67.out +aa0e85c2a30db6ce7b21491b5a33b467 absorptionpol_res_68.out +9c94a3f052cc8cc0389fc08d3a97bd12 absorptionpol_res_69.out +1a348e45d6ee8e738b2bd75af9483952 absorptionpol_res_70.out +7f8f466aeba20579c3fc4770c9c34c13 absorptionpol_res_71.out +6c3c4508feb9810eba585394a73b86d8 absorptionpol_res_72.out +20c8ff9d011e54109f29c043de9336b1 absorptionpol_res_73.out +c431cbe846a3d716631c2995c32a3fc9 absorptionpol_res_74.out +3f5a0176fa2af1ca85a141f5bf0f8a89 absorptionpol_res_75.out +2fb614c5eb27486e34fb4edf61db5584 absorptionpol_res_76.out +c5bb60e25121490bcd58a16c4101dac9 absorptionpol_res_77.out +1447d26390502a2ffcd1ad8e963583f8 absorptionpol_res_78.out +880de34d06dace1860021937f1f7937c absorptionpol_res_79.out +3eac559d6e67985d44c61f828c90f348 absorptionpol_res_80.out +832129e37c018c9f55a0e7e145d59d82 absorptionpol_res_81.out +43e93709de800b744c3a31d65e16d446 absorptionpol_res_82.out +4561ecca839caae1091eb617fcdfea97 absorptionpol_res_83.out +b98c306eefbdcb296416409573efe38f absorptionpol_res_84.out +a95bad4f708c810a5e56d98e32450c63 absorptionpol_res_85.out +8140c1509163887c9f2952a79881709b absorptionpol_res_86.out +3fbb09e642684e3ac15ad37e308eb71d absorptionpol_res_87.out +b021c8e597a7d9b8652718689fb84a20 absorptionpol_res_88.out +2f190e86345ed310a57f4de8f87c4591 absorptionpol_res_89.out +da8260a2cca92c8da42c13350685ad29 absorptionpol_res_90.out +37076f0b07437c2ba800cb002d9c6725 absorptionpol_res_91.out +36336d8b53de2c9f8681ccc5c299108b absorptionpol_res_92.out +ae70c3eb753ed6c25fbb825ddc3c4bad absorptionpol_res_93.out +0ecc4863d58704e350350829cf53d84c absorptionpol_res_94.out +2de6dc21be228f4bbf39aff52d5e66d4 absorptionpol_res_95.out +ebf1ac4f367790261bf860c181e0d77c absorptionpol_res_96.out +813cc06e7e62219b3ad3ba1f478ac873 absorptionpol_res_97.out +66dd3ecac672fe8c4dc786fcf84c3bcb absorptionpol_res_98.out +758116706e8cafcf3fe0b6da096993a8 absorptionpol_res_99.out 6fffc8a4adefb2119fde9ccadbff8151 bflist.out -491efef6cd9433a7ea28bbc32837cd74 deposition.out -502927544da3e8b8eea839c11ed29449 emission.out -9bc9019ea463ae7e6eece72cbf38c750 emission_res_00.out -5a7020c88d8c1cfcefe890784508e5ac emission_res_01.out -4e78327fcb930b0df0b3271f212a7afb emission_res_02.out -b14f2da2306961f02f32d9645dafff3d emission_res_03.out -16129a8798f914cce00a037c6b7571d0 emission_res_04.out -73eede2e57a2bf9a266e2ea63adf1993 emission_res_05.out -3ca81f9cd246bae0331718a6ef00c4c1 emission_res_06.out -338f9e95e2e68334a6449c48de74eac9 emission_res_07.out -07cfc7d9bf181d6ab4e1b2b9a0d7b333 emission_res_08.out -996fafd2eb8177c5eea8cca5c4bf4d66 emission_res_09.out -209da0be4412ac74c0e4e395fa8cbcd7 emission_res_10.out -50ac72b559ddb5fbe7266b664ab9f3b9 emission_res_11.out -4a7438a25d8d692bb012b96eb294f201 emission_res_12.out -0db74dd5eb1f026c43908a9748e73539 emission_res_13.out -2776c45bd44ff3a47f0a3813f98aac2e emission_res_14.out -0ad5b668081e8868855b980e7340c0e8 emission_res_15.out -de24e106ac74f19ef3248db6897c745b emission_res_16.out -81ddbafd7b364979bd7ab9b9f1926c98 emission_res_17.out -5c64416af54a4861c4d39771523f4186 emission_res_18.out -e21749629d9457175212f1e8926a0804 emission_res_19.out -fe2174f9bbefaa056eb2b464a5c0d02a emission_res_20.out -2040caeeafe922bd878b1972cb46d562 emission_res_21.out -ca55ac5ad83e620a647b33de922fd636 emission_res_22.out -b0f4240a06043926c71eb2aae6501f26 emission_res_23.out -0edabac70a085a3c9794ee3259f4b7eb emission_res_24.out -27f9eaff54cf4b543dbfa6fbb5a1e6e7 emission_res_25.out -3e168f770ab1ffef5e60975714172872 emission_res_26.out -433b682880dc74c6b052ca1924221e17 emission_res_27.out -c2ede0e309310482fa45eee48cb28773 emission_res_28.out -94b902b7397674b241c3c5f85e9e90d1 emission_res_29.out -d38129be1aef82fe50dbe462367fbab1 emission_res_30.out -22ce6774545d49f2f1002a0cc18a64d4 emission_res_31.out -9d6448c779171b29c30ef5515aae76d2 emission_res_32.out -b0f5d645f340a2b422bb09133768b9f5 emission_res_33.out -240712cc988895794464c19dad92a3f8 emission_res_34.out -eb45488d4bdc34ad758fe67a3c10623f emission_res_35.out -2be6cacbf968defc07c51d4ebfa5f855 emission_res_36.out -5424782cd71eca064f015a598325e392 emission_res_37.out -6c744cc80d75f0f72a8f4b2af7d65892 emission_res_38.out -827a6cec22fb3b949be47fd23a80fa90 emission_res_39.out -597293667fad5702d5ffc6c282ec33c7 emission_res_40.out -0272946cf8dd99a5d12e9e569b107c2b emission_res_41.out -f44dafb6472dca7a1ca4a9d37b5d8edc emission_res_42.out -29d3278fc717042e3f02cfe35e246bcf emission_res_43.out -803a8688310d5d6292691ad96dc6c3a6 emission_res_44.out -a19f51e4d2430ba689c87afe481b14ed emission_res_45.out -b91bf4d4df05d2a45cf0c121d716f7ba emission_res_46.out -38855471be3da18c66092e3e9576fa19 emission_res_47.out -ad8dd1da747daa176bb5f835bfac4dbe emission_res_48.out -369cc834a3d87f222ca3a80cbaeee4dd emission_res_49.out -1e59adc1f35466b780663850e6ea410f emission_res_50.out -f636cfcdaaffd9441cbe0031bcc3004e emission_res_51.out -81a63590bfc66b0538e95f39afdc4004 emission_res_52.out -21c34c3d7001269daa63cf69acd1c5ba emission_res_53.out -88cb47409e9fff5e52582440b2663efd emission_res_54.out -ebea2931a2289e7c30da4f6345abd351 emission_res_55.out -952d6a0ef1982f7540e9a7d071bb00bf emission_res_56.out -964565f92d92b8d159490d85a84f6e92 emission_res_57.out -0d33f8134ac0660bca5c55c803a4e05f emission_res_58.out -d788757f0ab835fb68e602fbfbb131b9 emission_res_59.out -a399bd2ccf0e164d87725b35c28f89a0 emission_res_60.out -2aa908c0244accfc8ec9b57d940d26b2 emission_res_61.out -0dcc9494958c0cd42ddc0ac093d6e206 emission_res_62.out -c6639b129b92ea85d4b41c1f39407d5f emission_res_63.out -68afb3d74230b5db9ccf61e7962d85c5 emission_res_64.out -d871149b505fa1e70e74d6f0d3334317 emission_res_65.out -204a9c4d9e005df0ed7b5165a342a347 emission_res_66.out -6c77bd1b44102665b16363e45c028e3a emission_res_67.out -4f782e6e82be65f12773b62fa50324b8 emission_res_68.out -ee7fb054309085843b888715118ccb0e emission_res_69.out -eb23c89337b7747fbb89ecc5a63864da emission_res_70.out -378fdb6f6df14f6c657c4b407f2d50a9 emission_res_71.out -70231208c959e41799b9f0b9ce88126a emission_res_72.out -114a38a82110e3fd1a409b6c65a0ebc0 emission_res_73.out -dee8878bbe7fa73943f294d06c31cf02 emission_res_74.out -db632a8aa10434db61b95ee506a713c3 emission_res_75.out -1b9cf6e92199ff5b5019f0478dd2dcbc emission_res_76.out -dd800c22b7953d9db7c49dae269f86b3 emission_res_77.out -580c1b5a18ed97d8c79e5514fa1f41f5 emission_res_78.out -5c644555484e632a7bfbf7f143171657 emission_res_79.out -580ece85a5e088592e848a678083e815 emission_res_80.out -76ec3edd8321e6d4edd261793b7382e6 emission_res_81.out -a47e0a1ceb8d9007e558d0f82e32e6bf emission_res_82.out -0b3acffbf608745c4046c5e7fec5c325 emission_res_83.out -8a739655b699368081fce94d64f1aaae emission_res_84.out -3ab4fee514bf4ea11931f0164f886ca1 emission_res_85.out -5c70b24ba9400215c95d4544defb1b9c emission_res_86.out -956d34b963b455abd9cf2ca440b579e3 emission_res_87.out -570b0e756dca86e1c65c440ecf16eaa4 emission_res_88.out -4cb482e0124def2ad46e212d098074dc emission_res_89.out -bd26e3f7406a2fb71b3254918f1db62b emission_res_90.out -73acba6fae1bd862e2a379592cfc9546 emission_res_91.out -db5e23dfa43d4b31b1eb0f4cef3d9085 emission_res_92.out -abd7d70a01364d3f28b5bb02eb1b334e emission_res_93.out -3673b94a84e2e4f110d34b256dd63564 emission_res_94.out -d864cd313ddcb8e746cf66d65e8b698c emission_res_95.out -c74fa580fa40e4215ffc60f8986b1103 emission_res_96.out -1514072732ce38276c4cf283baefbe4a emission_res_97.out -27bf4cc3b88e41ffbe139b5bee5629fd emission_res_98.out -2e98ae0e4f871197a0b97fd44b086336 emission_res_99.out -c854d6bf0ff7932e349317853b94d3fe emissionpol.out -a9bb81f227543a9678c5a9996da2cae6 emissionpol_res_00.out -b57ab7dde3f4ec287b87758a337db3fb emissionpol_res_01.out -d3d57042ee724d4364d00b24c84c3883 emissionpol_res_02.out -160bb2931abdbe9bac2b5f2b3e5e314b emissionpol_res_03.out -80c5f5db14b9c262c986bad0954ecbb1 emissionpol_res_04.out -fb261252de6d632eff3f5d9e081ffe9e emissionpol_res_05.out -137439f16c3496176856176d154620b8 emissionpol_res_06.out -f526fe69d06ea8d4be52a8a46c3b6196 emissionpol_res_07.out -7d7a3670a4b308d4b54b74392bb2d4f7 emissionpol_res_08.out -88802d98c3823b0b7561f7e424ccd2b2 emissionpol_res_09.out -91bdef72366c336125479ee64523939c emissionpol_res_10.out -ae22edea9f1ebbaafe046e5f049d4cb0 emissionpol_res_11.out -28098a21b3c5df665ec1d5e06cf16c5b emissionpol_res_12.out -254663cbf9f90565cb73ed0847ee98ac emissionpol_res_13.out -a13a79397c0694d57801b1c5a0ac7f8e emissionpol_res_14.out -8c00144c5564ca41215df454df056db5 emissionpol_res_15.out -4442d25ed0dca8e6bff225b95ac6f632 emissionpol_res_16.out -a1eb980153f8f1ee4e8499029f6f88ef emissionpol_res_17.out -c66bc44619cebc2bdad46e60e1d9f743 emissionpol_res_18.out -063803f77145879dbe9027ae69c40067 emissionpol_res_19.out -5478d946b7b65b7d3de0640418317520 emissionpol_res_20.out -c40181ae7b731cab3d0224dd06794002 emissionpol_res_21.out -ab8d766fa4aba521e7e633b1f5395289 emissionpol_res_22.out -623515565a178833d70f0f90b9339110 emissionpol_res_23.out -3d9d2f934ee5b7eaab3968e1c30e07ab emissionpol_res_24.out -ee5ff49cdfc31315801dfd3352035e5b emissionpol_res_25.out -7cb604407fc3c41668136bf69ce908b2 emissionpol_res_26.out -845a85e3fbbb110a6d388a1bc05bcc51 emissionpol_res_27.out -c1e25ed3a7179e8c03ee9e70e7eab1e4 emissionpol_res_28.out -20c7221a4462d3fd3787e8340681b70d emissionpol_res_29.out -88e6d38f94f69fd274907986dd5a9fa4 emissionpol_res_30.out -34a74463a026bfaf9b04a67d0a926bbf emissionpol_res_31.out -9ea79636c8eed2db3f2e39d3c04de44b emissionpol_res_32.out -4914223a2857823ac9d20a584464de7a emissionpol_res_33.out -639c97594c09d29986303699316fdc38 emissionpol_res_34.out -35a16aa1c1860e87eea1c71916b52f2d emissionpol_res_35.out -d2458b89ef741c18a23bb1d8267c35ef emissionpol_res_36.out -7213a06a3a5f0997771f692d6645b02c emissionpol_res_37.out -3d43c9fe5ee824f4e83140bb1f3f6774 emissionpol_res_38.out -a7200f720a6bc20ca658678bf99bcd79 emissionpol_res_39.out -df0c16f3bdf5e117ce53d9f313a26e8d emissionpol_res_40.out -af5d31cf5c79c2eee17880f389048ea2 emissionpol_res_41.out -e9abdada2c047fb32da3cece8457e097 emissionpol_res_42.out -53c0cb79e3526794c137888c5da777bf emissionpol_res_43.out -145e807898e7b24a510df0b96389a28f emissionpol_res_44.out -f0bbf89b06174faead359105d554898c emissionpol_res_45.out -f8cd7683ff155cf3922b15264db17fa7 emissionpol_res_46.out -330dc344963d7cc6164a4bdc6dc2d571 emissionpol_res_47.out -1dfb63da371b87ba460c379b919769c0 emissionpol_res_48.out -be29b9e6cbd11ecd09a7f06049b8863b emissionpol_res_49.out -853221dac3325a35f0b43741c5cf0c0b emissionpol_res_50.out -c3f1e80588e486843732f832fd4e9e6d emissionpol_res_51.out -941ebb06b6d5cb27072df2277f8417f2 emissionpol_res_52.out -1f742358d384b445ad494a93f8b862db emissionpol_res_53.out -b7494228d63f70daa526d7d3d4398611 emissionpol_res_54.out -5c46ecb2e9dd19775fed8deb1f593c84 emissionpol_res_55.out -cc14f020ac80ca71f6670a451dafaa02 emissionpol_res_56.out -30e812ad2bf82f96fdbd20376d2fa9d7 emissionpol_res_57.out -de5476120f2171dc58c30141b5cdb469 emissionpol_res_58.out -ddc23ec3025c4f2f4ddc332a671d8dab emissionpol_res_59.out -7fa0fa0ad0e23ad08533acf8e9bc9055 emissionpol_res_60.out -dd542a4a912c02fdea1b5ce612cf033b emissionpol_res_61.out -d0f54d456c777c3cb8641c58e0976ae1 emissionpol_res_62.out -f02e4977487990f6f84eaad54b7dcb38 emissionpol_res_63.out -218c9e7dbcdcd5c5a553d29d62d5bb3f emissionpol_res_64.out -2c14c0c6ecccad6b9a2e5d0e9a3cc6b6 emissionpol_res_65.out -ba29d9b51f208777c7081f798cda9f16 emissionpol_res_66.out -29253be6243329529c88e3cd9efc89c5 emissionpol_res_67.out -27af7f8f126570d6b3835dae2e07feb4 emissionpol_res_68.out -ab98b983e5c0b9eed793746988b300f5 emissionpol_res_69.out -58f815d3658f4af61142a8ae92385f10 emissionpol_res_70.out -9e580164782ae203c5268d07374773c1 emissionpol_res_71.out -022102a4fd16e5011e5f254b78cb93da emissionpol_res_72.out -6ecbac20c9a979c8a87e4903f5982bdb emissionpol_res_73.out -12e7d01abc1bd5335d7629c53af0df12 emissionpol_res_74.out -cb45d81a5ff159a44b6d206d085da41d emissionpol_res_75.out -cc72ff03a4562a2e017e813799a4523b emissionpol_res_76.out -19af2ea07db949936daa23c2cf8f5493 emissionpol_res_77.out -419b61b3466a2149bd0e603b03ff7343 emissionpol_res_78.out -d4fb609716fa7d380ee560c8e52d60e1 emissionpol_res_79.out -8f384410c499901689ae96b3e773bb91 emissionpol_res_80.out -33c9edff522d1c38d30327deaedcb41f emissionpol_res_81.out -199ccfa225852e2e4ac231d3a2d69e07 emissionpol_res_82.out -4b5160df3b57b796cb3411a04adadaa0 emissionpol_res_83.out -eeb29883da6cce8eb940584c69a7de5b emissionpol_res_84.out -b59f09c63c54dabb4c7cdbf3c4e7b9c5 emissionpol_res_85.out -bac94757b2ea6318f7627d62b52afed8 emissionpol_res_86.out -1efdd68a0f1279b4871204b1949e0e29 emissionpol_res_87.out -aa55e4693919c2c3f92eee84916011b9 emissionpol_res_88.out -8ffbf77610fe02ed83fcef1a3c14c080 emissionpol_res_89.out -a0841badf113e85f07703a5e7a41683e emissionpol_res_90.out -411dd4a47e98c615cccf448cd056a743 emissionpol_res_91.out -56dd003a364777accb5ff1aea978784d emissionpol_res_92.out -7f76159bee5976a85a3966a733a67a8b emissionpol_res_93.out -1d772385f6d29f077cd5aad03ddb1858 emissionpol_res_94.out -a7a7fe80a1b68cade6d28ee0e58da560 emissionpol_res_95.out -f6332fc5917941b01b5e51edb712d8f2 emissionpol_res_96.out -5ead47e7a66b5e0f6a134dc85273ffc6 emissionpol_res_97.out -35837b386f5464ada1811bcdde72a8e0 emissionpol_res_98.out -1a8bbbc324ec56f897b591aa53ea0ea4 emissionpol_res_99.out -0101784adda0e7ec34f1255be1b5d6f6 emissiontrue.out -a2858c2c5ae2f0f2dc7e58145f77eed5 emissiontrue_res_00.out -04fa5ce58efd2bdc84d02c83061a8d24 emissiontrue_res_01.out -58393c39eea8963ba04fecf03e5121e4 emissiontrue_res_02.out -c6b32cbffc5e2a267d53f4c10cd45ca8 emissiontrue_res_03.out -74d96f2a809873a2889b4f1d7706a8b0 emissiontrue_res_04.out -b48071fece61dabddd6436852a9780d2 emissiontrue_res_05.out -502d8e3cb6d52484875b783db3083b3f emissiontrue_res_06.out -7c530d8a06638977df7ad7eebd7d0b38 emissiontrue_res_07.out -f590ed73917938b055e2e5c28d103586 emissiontrue_res_08.out -a45b3e85d5f65355e1c13f9362e3ea5a emissiontrue_res_09.out -a26fcc19ed50d06661c8924995259d1c emissiontrue_res_10.out -9ac4401344b1eac5f73104c529909e4b emissiontrue_res_11.out -0cb9deb03959d16951a682bf1890883a emissiontrue_res_12.out -31be854a1514854e8142a68bb4581f44 emissiontrue_res_13.out -6905f5769b430d5bd5138cbbbef1886f emissiontrue_res_14.out -bde99aa9c1a07ea89d97973ecd7c95d2 emissiontrue_res_15.out -a099ec5205ee8453f67cf6202bc9cd94 emissiontrue_res_16.out -1b0913958d62bbb88df522944060d913 emissiontrue_res_17.out -c41ef62f1ca93eae4400a3c0fd014f77 emissiontrue_res_18.out -ae0171cb1d9c1eed4ec005e29c764eb5 emissiontrue_res_19.out -d95e89c2281599c68218f29c21320ff8 emissiontrue_res_20.out -c643e79fb80ae685f9246c7e2952b6f4 emissiontrue_res_21.out -52f2fdf3de99f4c4dac6586099a9c9b3 emissiontrue_res_22.out -7f800febebab6f542a2b558c5fa84089 emissiontrue_res_23.out -453ec61a14261d78d34a7dc662bf61c9 emissiontrue_res_24.out -30137c0a7cf995e92d2f9cca705c6ea6 emissiontrue_res_25.out -edec084bae0e0a08645cf8b930fcf8a2 emissiontrue_res_26.out -6101b8089b0bd78398483367878c0702 emissiontrue_res_27.out -95b18c0ae81a55bef3c0e4f8df284432 emissiontrue_res_28.out -61e10495f751364c46bbace1614f1438 emissiontrue_res_29.out -e0022e931bb66969cec4932376593203 emissiontrue_res_30.out -18338291034b9bf2bad4183887f8a4b9 emissiontrue_res_31.out -d5249b0f9a0ec8f16b08297139dd1c71 emissiontrue_res_32.out -9b46ec7401e7e851f12e911c960682fe emissiontrue_res_33.out -457f14943f93096a56efb1e39f518721 emissiontrue_res_34.out -29c0e84c4147ebbbe13dff47a0be8216 emissiontrue_res_35.out -d060828ded63a9c5a50c9327155e11aa emissiontrue_res_36.out -6c06f1614e88d76ce4446844783ae7fd emissiontrue_res_37.out -d01806bee2f9ea43e38791067204bbb7 emissiontrue_res_38.out -84edb27ccedf10f5070fdd0fa84715ab emissiontrue_res_39.out -5bd836aa2bde75958ca4f0ce8289b38c emissiontrue_res_40.out -97cc7a5f88c1da8bff7d9e0b330d77d2 emissiontrue_res_41.out -9b8a1e9e6be1039cb1f1622463660388 emissiontrue_res_42.out -b6b24cc35c0100ce58b7a82100c2459a emissiontrue_res_43.out -b4679ffe8407fc62c0a22dd8c7c428d0 emissiontrue_res_44.out -43d1b94502a88ff523730180cddd34af emissiontrue_res_45.out -bc9aa74a8002bb5077f229408f943be2 emissiontrue_res_46.out -d062cdd6a468a79decaedf02145a309e emissiontrue_res_47.out -de044cbea16c1b76be2a89da204d291e emissiontrue_res_48.out -a8e54dc4fd8284e83b680ab64c673b6a emissiontrue_res_49.out -0fd9d6260db8ea44f04590a77a5085e1 emissiontrue_res_50.out -15dca814fdfe5371b11e96e6620ee2bb emissiontrue_res_51.out -542d8b6b68cf0f29d6875f9469b9c0c2 emissiontrue_res_52.out -ba0dc2f199e3249611e68f51d0b6fe69 emissiontrue_res_53.out -d678f1d4db97b3557abf775334f40951 emissiontrue_res_54.out -a0ea8ad72d0d5ed9f9e8db3c48005c8a emissiontrue_res_55.out -61a58005c067d135b0f3ab220e89bc45 emissiontrue_res_56.out -0e55dfd4f912e75f6aa0e9e78a8e7f16 emissiontrue_res_57.out -babe31bee94f23f5f045c69789a73fa4 emissiontrue_res_58.out -86eebccdad524ff8953303690c3d5fb8 emissiontrue_res_59.out -bbc58ea843f546b23cf12f6a85a1fc0c emissiontrue_res_60.out -dd7a72ce575ba2b4c5220d25e58986d6 emissiontrue_res_61.out -cc501bedf5c883ed02e2848e8cca5210 emissiontrue_res_62.out -b24a8d1d3b7274f9585795f42a1397b9 emissiontrue_res_63.out -b23162aef0a4fb491b84def9a0feae4f emissiontrue_res_64.out -8c47c979e0eeb82b33881d2032200186 emissiontrue_res_65.out -6b1528186ef94e5447ba40973f3b5c4a emissiontrue_res_66.out -174433f574a9c2e49e34139ff5b822c4 emissiontrue_res_67.out -c3b6c402c27b2a7e9059662170411399 emissiontrue_res_68.out -a8c2f9ec5208bb1f2a19ad2975439686 emissiontrue_res_69.out -9ce9c9ba6666897e6913dafab22e0d8e emissiontrue_res_70.out -9a76483560cf9340b90243cde6aadcc1 emissiontrue_res_71.out -ef75f604d9860a4d0cc5f0761b8f9801 emissiontrue_res_72.out -a995e52fc2f9a39f64816c623910754b emissiontrue_res_73.out -3a08a9e9adf5fd893d79a9b387b5d3cc emissiontrue_res_74.out -6a834b1319f6a5014bf58d9f9b149154 emissiontrue_res_75.out -8006b1851ac4c2319df1a98683e1d72c emissiontrue_res_76.out -56826fe2e354846f88dff9351fc532c9 emissiontrue_res_77.out -e8668133e77479672a3a725cca57082f emissiontrue_res_78.out -06e427a7717deba8c498eb9529c4cfaf emissiontrue_res_79.out -eb79233cdcb472b8150c1aa1e86a0c0a emissiontrue_res_80.out -3ca076477c940dd44c4edc4a048992a1 emissiontrue_res_81.out -1128ee095ea3ba5abda8bb971e411428 emissiontrue_res_82.out -aab99902bc3fde17c0665c22029cb862 emissiontrue_res_83.out -aa1ef95692dd65dbb60d4cddcbba60f0 emissiontrue_res_84.out -25eb890d194c5a2965c7d31eae9f757b emissiontrue_res_85.out -8e763c8d68e56d50fc03d42678d0d6fd emissiontrue_res_86.out -d87bdfcd95d1935d83271dc9939d6997 emissiontrue_res_87.out -295be7ed90936b5dab0c836e06821a17 emissiontrue_res_88.out -ea4ea131cf3400591ed86c132325fc1f emissiontrue_res_89.out -e039eca441abaf57c1b0ed2f84804105 emissiontrue_res_90.out -9293e4140f09ad97e531bdd52b2aebbd emissiontrue_res_91.out -13d4f2ab781ee11e0a992b1028fa944d emissiontrue_res_92.out -6ada63c560d2b0a085f3a046aef03dcc emissiontrue_res_93.out -8420642870003e04774f1f8e2fac120b emissiontrue_res_94.out -c34dd88378faad679c7e3829fbb7799c emissiontrue_res_95.out -4484ef9f9034d789571798f6d034936d emissiontrue_res_96.out -e1d0bd6d218abab79440017004b121e5 emissiontrue_res_97.out -f44d6fc277c613d20bb84b0b316cd72c emissiontrue_res_98.out -331dc7a09d84248fb6647a4498192310 emissiontrue_res_99.out -4d50cf5a9c2a201c907971bd2731428a gamma_light_curve.out -eeafb42ed10c039fac8cd75fbf5debc4 gamma_spec.out +f650198b01b47569ab168ee36d86f46b deposition.out +0eba26ed1bed53bf1c383166b2ce8fe6 emission.out +988f72cb38ec27263a24d7193bb030cf emission_res_00.out +f50119e7867996e6923c7466c35c6720 emission_res_01.out +9ecd8bb67539fc133fb9122b4800f9eb emission_res_02.out +345e93f2aff1769fb2bf86225f034b55 emission_res_03.out +d994ffe7a1dfc847ab65c17e0f0d7151 emission_res_04.out +2ab1322d640fbb327af4ca37ee4ea089 emission_res_05.out +632c78aab920b943204f9d22da2a7b20 emission_res_06.out +f4c1af136dbea6fae10cbd0ddd2b0b7a emission_res_07.out +05d625f7c954dc0773e7d7ef5fdfc3d6 emission_res_08.out +f4022cb358ed797eb6fcf15131ef9882 emission_res_09.out +48b703743425e5988d7b7ec4a92a0cc7 emission_res_10.out +bcd4265fad4e78e7c35d4712861ee39c emission_res_11.out +a6538176565ec6a418ced19fe02dcb51 emission_res_12.out +2c59a1f7801b8c07012554fb6739967f emission_res_13.out +e97efba101532052fd89014e088c894a emission_res_14.out +18ae4f7188347e63e3cc834cef3a325c emission_res_15.out +37abff16f6e683ff062acfd6e8bdce57 emission_res_16.out +835a558146a3081634bc486cef1ec5c2 emission_res_17.out +024aaadbd097aaaa6855624cd54fb037 emission_res_18.out +94a7b6e5de26ba1db30fb59b9bceaa0e emission_res_19.out +9a2c55e580f66d731bd488a92170688b emission_res_20.out +863e5ce859c58e973591d394bf1701dd emission_res_21.out +f365519cdbdc6cdc097784d95a511e89 emission_res_22.out +6fe5d6f73551573a6fd0080a9d8130a7 emission_res_23.out +e3ef7c3dba6197da27736ae38b471693 emission_res_24.out +4db914f99ca927de64f73fa2c4d1c61e emission_res_25.out +6da16d2d6e328fb840971b1cf8dcb821 emission_res_26.out +87a1f5d9f55765642d3b28b5309f200d emission_res_27.out +7404289f7493499e3040d32f059a3c96 emission_res_28.out +78e069f86bff097c336fa9d2a8458722 emission_res_29.out +e48496a17f0dbb4e348f5478ec34e7b1 emission_res_30.out +11ee8e798f4e25de065b03831314ebd9 emission_res_31.out +d7ee0c46ca6d29710ce09ae06826e6ef emission_res_32.out +38b92bbf20b825db38caf6f918a19817 emission_res_33.out +4af5525556984fd574192ba4e147a1a2 emission_res_34.out +ede1c3ad39e7c2f7bf6cfb3a7e46668e emission_res_35.out +563c5397165d54c9e9002e263a4378fd emission_res_36.out +b72973833fce02050c869dd913659648 emission_res_37.out +b313c4abfcb7ae86d272d6c6c026e6c2 emission_res_38.out +94786e4d8cba04c4d91025f2890993b2 emission_res_39.out +58d82be9cd5a0b9bd4c99eb437858062 emission_res_40.out +8ca93297c001849c1727b38fe93f1848 emission_res_41.out +36318044ed86e563423eddbfb6ca4d29 emission_res_42.out +5420ce9ae185e22bff0fda5f06ad6ace emission_res_43.out +b7b4a634f562d0b628422012d39e78a4 emission_res_44.out +25f30f5a71ce60718a54114d978aa645 emission_res_45.out +8857c56c28e0acd22ee214a3d24fa5d0 emission_res_46.out +de7d46f7211828699eeaa9178ab8519b emission_res_47.out +aa0307cbca4bfaaefbc28e93afafa078 emission_res_48.out +d8e50a1ffb19aa9e152c69ea847657d6 emission_res_49.out +c8815ef06cb7aad6f6a0f0dc1c104207 emission_res_50.out +9fed9dc1d5c315d9f4b4972f62107104 emission_res_51.out +a4b1e671d5313b4ad2f3cc3b1b844860 emission_res_52.out +c90b9d069fe69f2e3035a21382bbec29 emission_res_53.out +618f48e527121ac7c9d4c0f1b67b808f emission_res_54.out +b272ab52dca79d623235cd8d5ffdbad9 emission_res_55.out +ada9721b4ca2ae93d8fcd9c5d95850ac emission_res_56.out +8c2f86451add972b069356c20a808503 emission_res_57.out +e69e57d8cf94f7b52cd1314fda44866a emission_res_58.out +a6a86ddea1e46a02ac4f13f834d979b0 emission_res_59.out +64a12b69d4a8ae2a79666946300464ee emission_res_60.out +93b8003d856a816027eb0bae30401b59 emission_res_61.out +f2c9e35367e5cd50f693f68f32296b18 emission_res_62.out +502dc0c8128308b2509c0e23dd7b8ee7 emission_res_63.out +de78383d3c17447dc0399456eac6840f emission_res_64.out +39c8da259cff50fab6a2e82df34ca883 emission_res_65.out +8fba8aa3d934b06b77707e3ec2d9df6f emission_res_66.out +c6f8061fd57984f35921dbc6c6ae79e8 emission_res_67.out +b90cc837e238be46e9ce15f186c5ee90 emission_res_68.out +fcf71fae62c3579dd750971e647ba7e0 emission_res_69.out +c933cd99e4d294772a6ab274446e08e1 emission_res_70.out +21be865f268dedf55e6431ae54bf3434 emission_res_71.out +eaeba0d06e40b260e3ead5bc2c9bfd5e emission_res_72.out +01f43bea4a0407e674ffac6636b8728c emission_res_73.out +d7af6f11b2f91ab9a6d65e486aabfecc emission_res_74.out +876362688ab858051283d5b55090b85a emission_res_75.out +ba2878ccffe2053c6791cd140dfebc57 emission_res_76.out +bebada7dd0ce54535d4e9cfa97e701b5 emission_res_77.out +98e1a8fdd8e94ba56479cdea05b8c3c2 emission_res_78.out +31d20da7f1e3ccb197fd37c49834d85c emission_res_79.out +7acf09f79e12ef19eae1b506f841ee3d emission_res_80.out +032b5b24fa6c0e6ca881d288c1cac12e emission_res_81.out +fb11abed8a3f3425b41f77309f13bb31 emission_res_82.out +c58ad26d31832e42e5a554bac5dea629 emission_res_83.out +6fe698d573199413dd3e292c5b5d6fcc emission_res_84.out +6aa1eceac0903582af3381a069a70813 emission_res_85.out +acdaca1e6da526dc27d4c4a2c7f10b69 emission_res_86.out +227c2432b26bc91a9d6e07c9abffc0dc emission_res_87.out +522f7e62ff8bf673ea440790c05d5444 emission_res_88.out +e52a48ce77af3a373328336cb0044fb0 emission_res_89.out +27b2520ca712e56ee7482493833f88ef emission_res_90.out +c02111ece8a69014b2da5bb98fdec9dc emission_res_91.out +e3d224a3bb6ab56c5cff9cdc3d455f11 emission_res_92.out +96d2658f961b574e7909f28c00f922b8 emission_res_93.out +95578406173f79c33044d220013058ba emission_res_94.out +1b36e3f0f0ec86fc9d3b6e92f0f3c7a4 emission_res_95.out +ff0e8b342fd922d56aa27e627e95143c emission_res_96.out +23c10d8a41b5d8279d3461b56ee75684 emission_res_97.out +92b8ae474362eee62d63261174a0970a emission_res_98.out +e9a47e7d32767995bc9bce1b188ae26a emission_res_99.out +2526d5aa0c3a1899e68a12201ad8f311 emissionpol.out +a646d6947bf49889394893e07ffb9a08 emissionpol_res_00.out +3aaf74cf42b9e03eee5a43f41b50b6ee emissionpol_res_01.out +251e494153987dd20e59b757d6b1c016 emissionpol_res_02.out +98231392bf8762cd66c5fb389943cfa0 emissionpol_res_03.out +6ee49f3caf21014d8d5f622e0fa69a19 emissionpol_res_04.out +ea49d0699e415758a060456ae5fe023a emissionpol_res_05.out +f26665f540df879f79763038c508e454 emissionpol_res_06.out +829773210c9c9c47f45b62a0b32ab8b9 emissionpol_res_07.out +00f8ded7885f372332ad8dca685a0290 emissionpol_res_08.out +726c60ab27d68278d12e210b4dbea611 emissionpol_res_09.out +1be9185a5e8ecaeff0a7c4cbf243ef29 emissionpol_res_10.out +9f9d586249ce84cc4913a4ed720d0fe3 emissionpol_res_11.out +799e049c1a632593482658be47b19981 emissionpol_res_12.out +3ba5b171b0205d07224f942498b22f0a emissionpol_res_13.out +57b332a16497c45949b7d5f764275c14 emissionpol_res_14.out +dad9f1f4dbaa04875de8d0a2590da1e8 emissionpol_res_15.out +4fdc3fb59027aa62f28d486c8b4dba19 emissionpol_res_16.out +cfac4a065ef07c61bf9c2fa984fd9103 emissionpol_res_17.out +80609df2e1f70bf347d803b81dc79ff2 emissionpol_res_18.out +8ae9a7cf20a46331b38889f1720d9a61 emissionpol_res_19.out +0b1384a4804c13c4e451d1a180a78c4d emissionpol_res_20.out +e0be50682eb631ea46c5de023538fad1 emissionpol_res_21.out +f01617395b7fb002ac86bb279cd12f98 emissionpol_res_22.out +b48059d90b51cb32f9bb356f5adca176 emissionpol_res_23.out +145c9d54026208f4da9214cfe3da6eb5 emissionpol_res_24.out +ce6ac7c0782e13d7fcb0da760dca5c75 emissionpol_res_25.out +83d80069cd849e6f9484591184e2f48f emissionpol_res_26.out +b23315c9bed3aecead3d78c9fb1bb058 emissionpol_res_27.out +5f17a9bc49773edbaa274700e9a5c7fe emissionpol_res_28.out +72622f15e0dd523630beeaf5ed33d849 emissionpol_res_29.out +01db239234bb671617b46d14d6cd755a emissionpol_res_30.out +93b0dbac30a88946f8873f81fe09ebba emissionpol_res_31.out +597359ae2a1a8de19be6a4b072d63c2f emissionpol_res_32.out +8d7a9ad93e93ec25a51d3497bf84c9f6 emissionpol_res_33.out +27aa8eb9e2c5676ee0da784f46a1d384 emissionpol_res_34.out +13071f908c71726d6c146b461bedd3b6 emissionpol_res_35.out +cee094f01298ef7156f5da51dac06068 emissionpol_res_36.out +8bd0576974783e938b1b9bb17ed11b0a emissionpol_res_37.out +fcc4fd1504e57f053194089dd6dac47c emissionpol_res_38.out +2ccd1d77dde71ee2448f1f6c36100cba emissionpol_res_39.out +6e140a7a00cc512b83a9799bfa61dbc1 emissionpol_res_40.out +1ec299702ebb60e0f87fb8e5468fae47 emissionpol_res_41.out +b29d45ee1c816332d70aa13baf0e54ec emissionpol_res_42.out +773f4936e4df844bc724199d3ba99085 emissionpol_res_43.out +94b04179a7d32d2f0b0f0071baa6d3e2 emissionpol_res_44.out +5fdbf3e858aa90cb41547a315763b7b1 emissionpol_res_45.out +4465d64baf57ccc4526763460ba7b8e5 emissionpol_res_46.out +01abc9320380a295250dc67c28ed091d emissionpol_res_47.out +47f5a54c5599018181c081a6502cfc8c emissionpol_res_48.out +6e3c9e77962a27c8ac844ebe72272ec6 emissionpol_res_49.out +5e5cd4398cc92a12f220e3e9d140643b emissionpol_res_50.out +18a5fd14b037a597487d23d575fb28c7 emissionpol_res_51.out +75280d6b6cdc910a9134aa7d535a985c emissionpol_res_52.out +161f497438a83e4a7cbcba7592c60f75 emissionpol_res_53.out +a507a4c88dcad920c2072a07e987506e emissionpol_res_54.out +c7f26655a17a8fd4445aa05814ad7d5b emissionpol_res_55.out +9063ce5fdc2739d294053fa553aa6161 emissionpol_res_56.out +737cafedf57fbe89d6b92ad01f720e19 emissionpol_res_57.out +51161ca8019b141ff372ec09ec34987e emissionpol_res_58.out +60ca10258f28e458cb9bda26b2917481 emissionpol_res_59.out +e769529c10d61c87170381d9d706bebd emissionpol_res_60.out +ebd5df12a203a55e928ba764719b2719 emissionpol_res_61.out +1d4c28bf7ce73a2ad5d6be59c2587d0b emissionpol_res_62.out +2a9b0b0fd741fb79d6a86ef4631734b6 emissionpol_res_63.out +d1a264dae1dd1e261f8363fa7906bd1e emissionpol_res_64.out +fefec12cc449acb63c4e631dacd85a68 emissionpol_res_65.out +8ad2bcaf00cd8b87ed28ccdc955cb0c8 emissionpol_res_66.out +7157f956fec93d8686e205ecda764107 emissionpol_res_67.out +a3f8c1be4db2f9d3fa938fd868f330aa emissionpol_res_68.out +47102e2026b5bb0686da3556a593c35b emissionpol_res_69.out +9f7bf5f525deb7f88ea3e00efb541091 emissionpol_res_70.out +9bdfc22211de203609d78cb41b0a9e26 emissionpol_res_71.out +6e42b8b80c3c89fd4c6fcde145cccc41 emissionpol_res_72.out +0faa250d87a2534fcb8e56e7eee50b16 emissionpol_res_73.out +012ab88bbd191232058b1e53e43f3eef emissionpol_res_74.out +7331530a299a85b80f63f41cac1a9e87 emissionpol_res_75.out +b1287ea2766c5f695b64e6f28544aec1 emissionpol_res_76.out +88bbe194484b1c1470a160ed69ed2594 emissionpol_res_77.out +4e450b82f5947c824ce0b5e6213ec9a8 emissionpol_res_78.out +c02d783f4a225abb351ba3a557fdf38a emissionpol_res_79.out +e156dcd77e07f060df38539702505f90 emissionpol_res_80.out +230a2ffda4aa451fe71c2dcca359c77e emissionpol_res_81.out +bb34ecf8a685761ebb6a89b4f286a868 emissionpol_res_82.out +dd9746edcc6e6479212704309fe67ca4 emissionpol_res_83.out +7c0cc67157e4924efa4dcbdc83c3dd57 emissionpol_res_84.out +189465ea81fd2f4ac750b6648c249211 emissionpol_res_85.out +60e67857a9061696031692916156e47b emissionpol_res_86.out +03ea8de68db82737e7f86e29897ff9e0 emissionpol_res_87.out +8e2c5428c9abb033feaadb8222e3b417 emissionpol_res_88.out +f8b9bea83113e44602e9fd0200e2cf7f emissionpol_res_89.out +5ae4a8fbcc65fa0b404f0033d24e686b emissionpol_res_90.out +5f08f30399df1390f593531f52391ace emissionpol_res_91.out +c8bdd34b1f72a035fb6af874a7a8a5af emissionpol_res_92.out +e92f5a88706cac4e04b90902b315841e emissionpol_res_93.out +c40b80b8e668c470cc7898c8b1e2d43f emissionpol_res_94.out +5054bd10e52808156d253f32a124a67e emissionpol_res_95.out +a4237144571a7c2085f890f593b06c34 emissionpol_res_96.out +fe1c5a42bc542bce5566be674dbe099d emissionpol_res_97.out +5ddde7c4ebfaea939cadb2787ab10009 emissionpol_res_98.out +81266788e141739778f1ff3c6346c0bb emissionpol_res_99.out +d22634307359422454d5e0e5e566e841 emissiontrue.out +792f8ea5007fe18b87b62accfab383c3 emissiontrue_res_00.out +546d6075da2e235b67b5ede44b8ec4ff emissiontrue_res_01.out +a120fc0e870b2035895c391c418d903c emissiontrue_res_02.out +970c05fe2c92f2d0fa846b02bbb8b0a3 emissiontrue_res_03.out +6ebce5225d6cf217c44bd17a403581bc emissiontrue_res_04.out +8833f3da6194fce72904b28c65475c22 emissiontrue_res_05.out +b66de0c5a83fd648f70d8c5e037168e8 emissiontrue_res_06.out +5743c106a154dce61dc5ca7cb0016315 emissiontrue_res_07.out +2996744be540bb9d8bc7b215b830ac33 emissiontrue_res_08.out +8338bee211175834ed31ef75668f7063 emissiontrue_res_09.out +14c30ab21f73bcd1ff81ff484c5df294 emissiontrue_res_10.out +0404aeca70b6a43ac89d25024863915d emissiontrue_res_11.out +1255b449d43985352fcb1d7a8de91566 emissiontrue_res_12.out +b6796538e227e1449b0045db140f8b6e emissiontrue_res_13.out +6de0347b4bafe8cb7bc3c0668d3dc6d3 emissiontrue_res_14.out +e11d24366f8d4e25fda98ed8299e76ca emissiontrue_res_15.out +f8a8c5d198c8e975aaffb19c51c83d1a emissiontrue_res_16.out +76026e1f7a0086d414549fcc80e02559 emissiontrue_res_17.out +7b2b1a79b366d2aec5fb70b9a2e31d40 emissiontrue_res_18.out +57a16470c83796045ddc0ec6cee2b48d emissiontrue_res_19.out +d49cace307d37419d6c1e6b6c60dcb0e emissiontrue_res_20.out +935b417f0ac571147cbb8b852dae6e3f emissiontrue_res_21.out +d1ba3f5996d8df7e27aea082633d38cd emissiontrue_res_22.out +db9f2853da60388d3df595d08117de79 emissiontrue_res_23.out +eb4115a0d53bbe6360039c9a861d365e emissiontrue_res_24.out +89f91fa4dfee7c6e55f5cd71b0441576 emissiontrue_res_25.out +1ee8c05b5c0897804e6a746ace419a64 emissiontrue_res_26.out +7b30a0736f6fa669cd5c258c621fecfc emissiontrue_res_27.out +eeb4494347be6155d5a0aaa414e9ad1a emissiontrue_res_28.out +6f9581951dadab12982d7711ba0cfb82 emissiontrue_res_29.out +3548b1bdfa0bcf3271ced792e65bb3ef emissiontrue_res_30.out +dd23b2fbda52fb78f5cf4c7e9d2e594e emissiontrue_res_31.out +f3efc872f78208a455232be65db080d5 emissiontrue_res_32.out +2d0095802f2fabfb1adebc0344fdd390 emissiontrue_res_33.out +0790212696107bda913d2c3f322afd8d emissiontrue_res_34.out +48a85ee80533689f4a4c3e7565f3b791 emissiontrue_res_35.out +fed23fc98afa36e018aad1e0dc6942d5 emissiontrue_res_36.out +ff1a3d372c9cdefba2f593fefe8e1f41 emissiontrue_res_37.out +1bd2bc6e7607dad8a8aa911b45017539 emissiontrue_res_38.out +71f7323060318d47f77fe4297cf34d44 emissiontrue_res_39.out +0e03b3937918852a4c5516c26aedc444 emissiontrue_res_40.out +d127ce956d0810f2850576c045db33c6 emissiontrue_res_41.out +66e19b49f298c980c91c68dcbab3f3ca emissiontrue_res_42.out +58db006324fcce2243a1acffb3e66b2e emissiontrue_res_43.out +1f7113f0507975739f491f2d67099453 emissiontrue_res_44.out +bae21c95588cf267ebda51888c703862 emissiontrue_res_45.out +b046efc922221c2a11f2000b3bf81eaa emissiontrue_res_46.out +3f633ae5d52a0179289c074f039624b1 emissiontrue_res_47.out +714c2dd9fd50462d9dd3fea1412d3dbc emissiontrue_res_48.out +0e3d25d79277196ecf91bf05c8db1a38 emissiontrue_res_49.out +75cc3d3a1cd2fb3150dfa5b29e69c175 emissiontrue_res_50.out +5fd47d19fc0efdeb4f60e79fd1b9890b emissiontrue_res_51.out +4a96e3eb555286c40eef6768302d7a90 emissiontrue_res_52.out +6133ff8b4a8addb1f4d2bc21e31621c5 emissiontrue_res_53.out +52b4efafacdd3d67927de32ccc9bc370 emissiontrue_res_54.out +13311b1c54678124a1e745a471491992 emissiontrue_res_55.out +b6465b7f3643351fdc0a70047b4e3b2f emissiontrue_res_56.out +c55efe3826f48e740c369377f485532a emissiontrue_res_57.out +3ceeb24751cc78ad26fb4180eafd3b92 emissiontrue_res_58.out +4f80743d5d4176b8f0966c82e189ea52 emissiontrue_res_59.out +084236bd3d9601e35d025ca39c6e8aa0 emissiontrue_res_60.out +6c9c8aeebc9d03245d348b744b61d122 emissiontrue_res_61.out +06fbbaf07a8aca41d5a4a604ad75e7f8 emissiontrue_res_62.out +aa0ab6da1c813e0908b9ea7286c5636a emissiontrue_res_63.out +d943c95b730cee26d0f9e54426c3c778 emissiontrue_res_64.out +a1398bff72e00b9c8afef33944cccbd8 emissiontrue_res_65.out +f2a2a9402e83da9f090d1cd5e3c9a553 emissiontrue_res_66.out +73a15a467fb63c5ea152375e8cb10192 emissiontrue_res_67.out +5251598256eac4fd303b2ca1d4f7f780 emissiontrue_res_68.out +05e1c65667899db0d80fdca164d2ebab emissiontrue_res_69.out +9d3271f2e702c1159dcb591741663e30 emissiontrue_res_70.out +92cdb8aadad49dd873f1c13d332506b4 emissiontrue_res_71.out +6b8884aeed6e0cb33fdcfe7535080d7f emissiontrue_res_72.out +a3b733badf38493263dc26c34bb989ff emissiontrue_res_73.out +4e881ce09a498af4492f8b1bf3ca6237 emissiontrue_res_74.out +cae05ce9ecca843d1e197fbf03e631c4 emissiontrue_res_75.out +13680258b54b91645a65eab828569510 emissiontrue_res_76.out +2d00ccfe8950635ead1b3a67763a3291 emissiontrue_res_77.out +7fe4b1ac281cc74715b7a8cd1e157ac5 emissiontrue_res_78.out +4d0ecd7c78b095ed5d9ca96b36701b4d emissiontrue_res_79.out +9ea1a86f53d9a6f26a3c977a50152c12 emissiontrue_res_80.out +3560315ea522dc39eb210244afacb531 emissiontrue_res_81.out +cdbdd5be434042094c9eb3c4dc7bbaa6 emissiontrue_res_82.out +ff65e8993590aa82ec0ef26f387e0d20 emissiontrue_res_83.out +f736852c1dd2a2245347f4988db0ff7c emissiontrue_res_84.out +e8beafeced043561f954389b8bd1de4d emissiontrue_res_85.out +bb2bc2b36a5d2f038c55a066ea63f88f emissiontrue_res_86.out +b0ada059784dba5e858c4d112975c754 emissiontrue_res_87.out +89df46f26a44b37975ad74888cd76b06 emissiontrue_res_88.out +8e1a0cae69eeca946bb5978c1a82d641 emissiontrue_res_89.out +a59c48ad8f7389d137d0f189941b6b7b emissiontrue_res_90.out +47d86c414de92767b9fce5edb62bf10f emissiontrue_res_91.out +38a3a29844aa4d9b17c2e559352416ca emissiontrue_res_92.out +2300761171aa81a007f09ff9b99376fe emissiontrue_res_93.out +b0663dac106fd5f323ef385247f0565a emissiontrue_res_94.out +7da2a33bd6da961a7a5bb28b0bb08cb0 emissiontrue_res_95.out +423d64d49a27487cfd8544cc953743dc emissiontrue_res_96.out +aa52ea50c33db91f2109704d839be9b1 emissiontrue_res_97.out +5a79f21717cbcf03268ab031412b042f emissiontrue_res_98.out +3cfc4614cc4da027343c0d920040234a emissiontrue_res_99.out +a96a87d697ca41d4d02a25d44d22019a gamma_light_curve.out +278860838216f65b2df46ff7bf493ef3 gamma_spec.out 057b226c371f3819cba5e04bfea3d114 gammalinelist.out e08bbb965fac36412810b8769a13ab9d grid.out -0daa058efd056d5f72ebf54241d7c0e6 light_curve.out -eccc661f70e5884fcfd5ff50aa4a2032 light_curve_res.out +37ce27fcc45a6837ecc986ad038c112b light_curve.out +0691b11f3a8871fbe0b141ca8e551910 light_curve_res.out fb8c9b73ab7c5bb1fac556612d74812d linestat.out 07e400ff3495dc0b972ebe785db8b3c2 modelgridrankassignments.out -aca477827eff178e3cc7d69ef34e022e packets00_0000.out -ad403f7b1ce58262cab162d8c52e6899 packets00_0001.out -0a2517a98fe85dd57f6d4c6a0abc7320 spec.out -98ba9a554d8244a0c8bffd8c9d73c7d0 spec_res.out -127cddc13e2026653ec677bddaad858a specpol.out -17c348e654207dfdbbf0915c01db7be4 specpol_res.out +1ce914331cf5e604e7d2a6949d47f2bc packets00_0000.out +898ed91664f4c73c438cf05530c63994 packets00_0001.out +d88b1007563f469de4c3fa6485354950 spec.out +4389f39981b63d4db9c453fa8b8f5ebf spec_res.out +0463bd17f8c10622f2f13c1d4da2fb9f specpol.out +edffea9cc8b28c23286d9438a28f7924 specpol_res.out bc01f046eab9bf3802149e0ff63d5069 timesteps.out -fc30efcda41ed14972c013e74098102e job1/estimators_0000.out -1c8d82d3032d18549305c5637349306b job1/estimators_0001.out \ No newline at end of file +6ea207f7cffa562e62f9d2311376ed30 job1/estimators_0000.out +676fc28b1c1145b219cf3d7a93b2d589 job1/estimators_0001.out diff --git a/tests/classicmode_3d_inputfiles/results_md5_job0.txt b/tests/classicmode_3d_inputfiles/results_md5_job0.txt index 24942f464..20077b81c 100644 --- a/tests/classicmode_3d_inputfiles/results_md5_job0.txt +++ b/tests/classicmode_3d_inputfiles/results_md5_job0.txt @@ -1,17 +1,17 @@ -c524b815b9d27074f1981c43ac29693f absorption.out +3d2fdec1e8d7be5d284686950fa8919d absorption.out 6fffc8a4adefb2119fde9ccadbff8151 bflist.out -5f8cc880b9341445c00783bc8e1bddf5 deposition.out -01453920190b555bc7347234622cd611 emission.out -b8fd93be83fe661d22bbbf0f53dce42f emissiontrue.out -e586cd6ebc62208341b1fb1c37d324da gamma_light_curve.out +e77549779647478dae4195e0c7440c75 deposition.out +d267fc8e87ed6de0b6f02134959342db emission.out +9551c22a92df754a2c881a844156256c emissiontrue.out +2371265548b1da29928750800f62f4b7 gamma_light_curve.out 057b226c371f3819cba5e04bfea3d114 gammalinelist.out e08bbb965fac36412810b8769a13ab9d grid.out -086bd7e9f41ad4139bca7b8ba3954161 light_curve.out +065249d721a5b797eedb4dd8d564d34f light_curve.out fb8c9b73ab7c5bb1fac556612d74812d linestat.out 07e400ff3495dc0b972ebe785db8b3c2 modelgridrankassignments.out -04a6dac5e730e042af413f15bffdeabe packets00_0000.out -c318ca42d308319f959d3a0ed163127e packets00_0001.out -0f5340103bc6c36611dff85cc3058706 spec.out +19dd0f6482e8c2a8e5ad4c9c03633f5e packets00_0000.out +663b0393f95a92f6a0f0fd931957f5c9 packets00_0001.out +8aad0eabdebf722460b05185de9a1a8c spec.out bc01f046eab9bf3802149e0ff63d5069 timesteps.out -f88368939bc4312eaf65d44eef3eca46 job0/estimators_0000.out -d8aae79ab16f4ca2f64dc1c442b57cc3 job0/estimators_0001.out \ No newline at end of file +1a934a7e3ebea1474f6bf2c90fa8bb1e job0/estimators_0000.out +c30f3fc1c4e98443f219a528dfecc6c8 job0/estimators_0001.out diff --git a/tests/classicmode_inputfiles/results_md5_final.txt b/tests/classicmode_inputfiles/results_md5_final.txt deleted file mode 100644 index 5c078a97f..000000000 --- a/tests/classicmode_inputfiles/results_md5_final.txt +++ /dev/null @@ -1,23 +0,0 @@ -069938a09dfecd9cd8997f2bd925b181 absorption.out -aaf3f5018af7c2179f612f3d6c37d709 absorptionpol.out -c0604236aa7df99cda43e5c7bbe7b6f4 bflist.out -f0e6799258b54f35a38ab83a5fde2152 deposition.out -029bfae9cf2c93d180bc728324434003 emission.out -3723f2d7ef56499a02a21c61944acd32 emissionpol.out -30b4532c11eea8890bd118213441af0e emissiontrue.out -69c4e5cee569b5076d9e1d6f9cb7b796 gamma_light_curve.out -544d63ba01e9db28dc43311b3d738704 gamma_spec.out -057b226c371f3819cba5e04bfea3d114 gammalinelist.out -20bddb22b6f084a7abc105c210366bfd grid.out -930cecfe1ff351541acb69a6de613fed light_curve.out -5740f40190d45653e5fce57ddf577dc8 linestat.out -c4e4e8d00846618f3931dc01cf52615f modelgridrankassignments.out -19d6928e153b769249392f76fbf628c1 packets00_0000.out -2698549a6b2240a98444e37052e8a436 packets00_0001.out -7ddb0915c7fedb723d61039cc29443b8 spec.out -5f1f14fd268e13a0e7bf9a61b5766bee specpol.out -040c71f981716a2abf0467a82b1ac13c timesteps.out -99bfc68bdb59019cbde8ce02858391b1 vspecpol_0-0.out -99bfc68bdb59019cbde8ce02858391b1 vspecpol_1-0.out -d5768a9bad50b8105447a94a08affcca job1/estimators_0000.out -1f92c6a323f21823dbfe76fa340c103a job1/estimators_0001.out \ No newline at end of file diff --git a/tests/classicmode_inputfiles/results_md5_job0.txt b/tests/classicmode_inputfiles/results_md5_job0.txt deleted file mode 100644 index 18b7b27a2..000000000 --- a/tests/classicmode_inputfiles/results_md5_job0.txt +++ /dev/null @@ -1,19 +0,0 @@ -f3b413171a447c8f6f4130e7d9e79094 absorption.out -c0604236aa7df99cda43e5c7bbe7b6f4 bflist.out -d64db10eddac9ea86dc988e1314bce7d deposition.out -bc3fa0983482e1bec6cc58f0a3c672be emission.out -f864869c9eefb25c79390c5b87278fb1 emissiontrue.out -7efccbea018d4330c778f3a6ac7485d1 gamma_light_curve.out -057b226c371f3819cba5e04bfea3d114 gammalinelist.out -20bddb22b6f084a7abc105c210366bfd grid.out -66a130b6340f9786fd7dde704184db94 light_curve.out -5740f40190d45653e5fce57ddf577dc8 linestat.out -c4e4e8d00846618f3931dc01cf52615f modelgridrankassignments.out -32196c9763d29c3a46a50435d30f474c packets00_0000.out -43b382a8fd6f7180a5d5120e8a073311 packets00_0001.out -a10ad51bee9bafec0e8af851ab547252 spec.out -040c71f981716a2abf0467a82b1ac13c timesteps.out -99bfc68bdb59019cbde8ce02858391b1 vspecpol_0-0.out -99bfc68bdb59019cbde8ce02858391b1 vspecpol_1-0.out -2e37f4387a400276a61ba72530ae9e0e job0/estimators_0000.out -0134290c0abc1ec502b7d436f536e49a job0/estimators_0001.out \ No newline at end of file diff --git a/tests/classicmode_inputfiles/vpkt.txt b/tests/classicmode_inputfiles/vpkt.txt deleted file mode 100644 index 65d6c0eba..000000000 --- a/tests/classicmode_inputfiles/vpkt.txt +++ /dev/null @@ -1,14 +0,0 @@ -2 -1 0 -0 0 -0 12 0 -1 1 2 6 8 14 16 20 26 27 28 -1 10 30 -1 1 3500 10000 -0 100 -10 -1 -16.5 21.5 -2 3500 6000 6400 7200 - - - diff --git a/tests/kilonova_1d_1dgrid_inputfiles/results_md5_final.txt b/tests/kilonova_1d_1dgrid_inputfiles/results_md5_final.txt new file mode 100644 index 000000000..f8bcbf0f0 --- /dev/null +++ b/tests/kilonova_1d_1dgrid_inputfiles/results_md5_final.txt @@ -0,0 +1,18 @@ +e1bbb9e147672e32bb50fba260343584 absorption.out +f9bb214eb7f1ac22791a13c8025c4887 bflist.out +87aedf284bbaafae235976a623f1c1a5 deposition.out +7f7ee4926056b26206170ae330594d99 emission.out +4b1b8d917ab7f915b6f3b1afcef48011 emissiontrue.out +893ba3deb7c680605311de7f18ff01a2 gamma_light_curve.out +24ad8d7469380a561eecaedffde4e334 gamma_spec.out +4af36569cc2db94b41cdadbc03354ac4 gammalinelist.out +7db21c856b5d2784b14eabfd22e5b837 grid.out +9b198e6c609babbe223c63018acb7979 light_curve.out +9773becefdfe4afffb041b703210c67c linestat.out +f5b097e63480ea2b54bb88459f72b19a modelgridrankassignments.out +33872793c9626adce4163a6f92f225bc packets00_0000.out +0b33390bb2afa6eb72e3eb66f8c6173c packets00_0001.out +5fbbcd0c30de4611d0f6e8e3b7644174 spec.out +a351f1711fecd60c023d0ba7332092db timesteps.out +6a6ebdc0648b2b21aef452bf8175f133 job1/estimators_0000.out +bc4574bd849763bb85d1c3811f193e5e job1/estimators_0001.out diff --git a/tests/kilonova_1d_1dgrid_inputfiles/results_md5_job0.txt b/tests/kilonova_1d_1dgrid_inputfiles/results_md5_job0.txt new file mode 100644 index 000000000..c0e23510d --- /dev/null +++ b/tests/kilonova_1d_1dgrid_inputfiles/results_md5_job0.txt @@ -0,0 +1,17 @@ +7e47b382ddacd759ae33771c8fba1bc2 absorption.out +f9bb214eb7f1ac22791a13c8025c4887 bflist.out +6920ce785631e113d3bdec0e8bf42f66 deposition.out +43641ad17d13b4d07954d7fd9a45864a emission.out +d23d4ea71b94b1a4fb706f49a4c8c002 emissiontrue.out +b82ac74d554da3f567302ccbadff7366 gamma_light_curve.out +4af36569cc2db94b41cdadbc03354ac4 gammalinelist.out +7db21c856b5d2784b14eabfd22e5b837 grid.out +31be3b86c22c343df5b2f0f10c2edd0c light_curve.out +9773becefdfe4afffb041b703210c67c linestat.out +f5b097e63480ea2b54bb88459f72b19a modelgridrankassignments.out +d9dcb4378a7ed332f79a5071bae91a9e packets00_0000.out +b0d755d49c026bf4e67bba200191fd35 packets00_0001.out +8269008eb999358088439c0330a996fd spec.out +a351f1711fecd60c023d0ba7332092db timesteps.out +d791e9b02393ab142c5a3e616dd1b668 job0/estimators_0000.out +944041c0ef95bf74c720c433505efe86 job0/estimators_0001.out diff --git a/tests/kilonova_inputfiles/abundances.txt b/tests/kilonova_1d_3dgrid_inputfiles/abundances.txt similarity index 100% rename from tests/kilonova_inputfiles/abundances.txt rename to tests/kilonova_1d_3dgrid_inputfiles/abundances.txt diff --git a/tests/kilonova_inputfiles/compositiondata.txt b/tests/kilonova_1d_3dgrid_inputfiles/compositiondata.txt similarity index 100% rename from tests/kilonova_inputfiles/compositiondata.txt rename to tests/kilonova_1d_3dgrid_inputfiles/compositiondata.txt diff --git a/tests/kilonova_inputfiles/gridcontributions.txt.xz b/tests/kilonova_1d_3dgrid_inputfiles/gridcontributions.txt.xz similarity index 100% rename from tests/kilonova_inputfiles/gridcontributions.txt.xz rename to tests/kilonova_1d_3dgrid_inputfiles/gridcontributions.txt.xz diff --git a/tests/kilonova_inputfiles/input-newrun.txt b/tests/kilonova_1d_3dgrid_inputfiles/input-newrun.txt similarity index 92% rename from tests/kilonova_inputfiles/input-newrun.txt rename to tests/kilonova_1d_3dgrid_inputfiles/input-newrun.txt index 7fd8c94a2..4918076a4 100644 --- a/tests/kilonova_inputfiles/input-newrun.txt +++ b/tests/kilonova_1d_3dgrid_inputfiles/input-newrun.txt @@ -1,6 +1,6 @@ 1281360349 # pre_zseed: specific random number seed if > 0 or random if negative -20 # globals::ntstep: number of timesteps -000 009 # itstep ftstep: number of start and end time step +20 # globals::ntimesteps: number of timesteps +000 009 # timestep_start timestep_finish: number of start and end time step 0.4 010 # tmin_days tmax_days: start and end times [day] 1.33 1.330000001 # nusyn_min_mev nusyn_max_mev: lowest and highest frequency to synthesise [MeV] 80 # nsyn_time: number of times for synthesis diff --git a/tests/kilonova_inputfiles/input-resume.txt b/tests/kilonova_1d_3dgrid_inputfiles/input-resume.txt similarity index 92% rename from tests/kilonova_inputfiles/input-resume.txt rename to tests/kilonova_1d_3dgrid_inputfiles/input-resume.txt index f042db236..24e7330c8 100644 --- a/tests/kilonova_inputfiles/input-resume.txt +++ b/tests/kilonova_1d_3dgrid_inputfiles/input-resume.txt @@ -1,6 +1,6 @@ 1281360349 # pre_zseed: specific random number seed if > 0 or random if negative -20 # globals::ntstep: number of timesteps -008 020 # itstep ftstep: number of start and end time step +20 # globals::ntimesteps: number of timesteps +008 020 # timestep_start timestep_finish: number of start and end time step 0.4 010 # tmin_days tmax_days: start and end times [day] 1.33 1.330000001 # nusyn_min_mev nusyn_max_mev: lowest and highest frequency to synthesise [MeV] 80 # nsyn_time: number of times for synthesis diff --git a/tests/kilonova_inputfiles/model.txt.xz b/tests/kilonova_1d_3dgrid_inputfiles/model.txt.xz similarity index 100% rename from tests/kilonova_inputfiles/model.txt.xz rename to tests/kilonova_1d_3dgrid_inputfiles/model.txt.xz diff --git a/tests/kilonova_1d_3dgrid_inputfiles/results_md5_final.txt b/tests/kilonova_1d_3dgrid_inputfiles/results_md5_final.txt new file mode 100644 index 000000000..f8d0fb41b --- /dev/null +++ b/tests/kilonova_1d_3dgrid_inputfiles/results_md5_final.txt @@ -0,0 +1,18 @@ +a28abc7f3400c76d3b38da6cc3815b13 absorption.out +f9bb214eb7f1ac22791a13c8025c4887 bflist.out +0ff0e2fc9adf68667ac4bcff8f240d4c deposition.out +858da30ef4cfe71f53759dbc7dedd1ff emission.out +56c691bbc3c3e0d93a32e209c64bfc3d emissiontrue.out +a24dd7054c3bc0c35be4e74a5f9e6ed3 gamma_light_curve.out +756a288eb4e4d171fcb1162c0ec8c3d8 gamma_spec.out +4af36569cc2db94b41cdadbc03354ac4 gammalinelist.out +17cf657837d7df2969e3e1540b183cfe grid.out +a180e52d4ee94f2d679a1320ca628b06 light_curve.out +9773becefdfe4afffb041b703210c67c linestat.out +f5b097e63480ea2b54bb88459f72b19a modelgridrankassignments.out +def7d4e67866038f5a075bc74d1d225b packets00_0000.out +a3bfac14bde7b6e25811144bfeacec4f packets00_0001.out +821414204b3fb0fab174b9895cbc6e68 spec.out +a351f1711fecd60c023d0ba7332092db timesteps.out +5d2348e48bb2d1ab37357fe5a90e0fcc job1/estimators_0000.out +dcf178e682d15f7bf16633e49bbf9bea job1/estimators_0001.out diff --git a/tests/kilonova_1d_3dgrid_inputfiles/results_md5_job0.txt b/tests/kilonova_1d_3dgrid_inputfiles/results_md5_job0.txt new file mode 100644 index 000000000..4acf72fc3 --- /dev/null +++ b/tests/kilonova_1d_3dgrid_inputfiles/results_md5_job0.txt @@ -0,0 +1,17 @@ +86efe2dfb75107386eb4a0a2b01825cb absorption.out +f9bb214eb7f1ac22791a13c8025c4887 bflist.out +fe69c73227acf3be8a84a9c77554eea4 deposition.out +badaf4d5686bac45bcaf19efc6eacb02 emission.out +1cc31f4dc885f52aa180cef4b1dc3dc5 emissiontrue.out +28454eabb842b47ba951914a57add3eb gamma_light_curve.out +4af36569cc2db94b41cdadbc03354ac4 gammalinelist.out +17cf657837d7df2969e3e1540b183cfe grid.out +9626cbeee57ff23233a67786179520ae light_curve.out +9773becefdfe4afffb041b703210c67c linestat.out +f5b097e63480ea2b54bb88459f72b19a modelgridrankassignments.out +a84d3d4a9c7d1f61394f1b903d5bb244 packets00_0000.out +627178c8fb51ac34030cd547cc9d268d packets00_0001.out +6fe9dc86f38f3b31814186c336019313 spec.out +a351f1711fecd60c023d0ba7332092db timesteps.out +d77d94d656fc59fd894cefffc97aca2b job0/estimators_0000.out +6b0031f1c76b0152f43013f4defc7e10 job0/estimators_0001.out diff --git a/tests/kilonova_inputfiles/syn_dir.txt b/tests/kilonova_1d_3dgrid_inputfiles/syn_dir.txt similarity index 100% rename from tests/kilonova_inputfiles/syn_dir.txt rename to tests/kilonova_1d_3dgrid_inputfiles/syn_dir.txt diff --git a/tests/kilonova_2d_2dgrid_inputfiles/results_md5_final.txt b/tests/kilonova_2d_2dgrid_inputfiles/results_md5_final.txt new file mode 100644 index 000000000..0e9cef292 --- /dev/null +++ b/tests/kilonova_2d_2dgrid_inputfiles/results_md5_final.txt @@ -0,0 +1,320 @@ +86a309ca9e8c8d7550f0157879510249 absorption.out +96919ce9810fac2b0dde28493f66786b absorption_res_00.out +22b381ff2e2f3d0bf5fc010ac3485470 absorption_res_01.out +f4bacea6bb489bed91e963fedb93a934 absorption_res_02.out +d235bf7e3c04ba0c86fdc6c4700fd60c absorption_res_03.out +3a7ec4ef4ab2d61f3f962a5d2e0d22e6 absorption_res_04.out +edbfd7a04d17fb4a8407dac1bac6f70a absorption_res_05.out +86b6fb4b0109ce56e9d8a1b4362f10ed absorption_res_06.out +a3f701f102b3108ac697da9d9e3a8dcc absorption_res_07.out +f8037e16edb908746ff773630bde63c0 absorption_res_08.out +ae615d40e80f0cd52216a3d534ae2992 absorption_res_09.out +09efdfa36442f72a327a0aa520f3de52 absorption_res_10.out +ac98d4364aa0c816e42306c12432e405 absorption_res_11.out +15d7fbe445503837e404d5aca87c0e5b absorption_res_12.out +e045b6c62fbaeaa2eec843279a6176f2 absorption_res_13.out +d1a3c09fb220cdc4f0d286f75811a4f8 absorption_res_14.out +51206607177af17670bd9ba08ccab729 absorption_res_15.out +c8897cfc8aec2e606bd44b3a5496f876 absorption_res_16.out +349b2eadfbd3017b4076f344ec532d83 absorption_res_17.out +4e065a36ea2c238d6326133a8ab5dd99 absorption_res_18.out +c9ec981ba1db9485e7eddb6e534e39cf absorption_res_19.out +ff4721e9ac1fa7d9f1f5e5bcc748bfeb absorption_res_20.out +5e4d721df0cd45677e28490e0952e21c absorption_res_21.out +4e61e8856163023a121ba3364fe899a7 absorption_res_22.out +e3fb216eec7c093bd60887236b04b0cf absorption_res_23.out +4de57786094488ecbf271c264a3a0cae absorption_res_24.out +5df39f1c10ed6bbb01cd79451320b6e3 absorption_res_25.out +6eb0bb63a5694435075070a4e04323eb absorption_res_26.out +cc421e29e02fcf28430b883118c3bac5 absorption_res_27.out +28e5184141266a447becfdc692969355 absorption_res_28.out +6d220612420d9dd0e0e8597fda16cc76 absorption_res_29.out +ae1a1b2e51ba43f890857ea39a62cc6f absorption_res_30.out +013872cd6659862f4e94684834e390aa absorption_res_31.out +f8054f64918dc629091873c8dcd412fb absorption_res_32.out +306abb0550492b74b725048b557db498 absorption_res_33.out +cd3b8735f2932d7fefd56225c8f3485e absorption_res_34.out +651895cbe121a17256bd2d811ab99f4b absorption_res_35.out +ca248c9c58576d405324a70f8061d8ed absorption_res_36.out +3cb2e279449358196a051e1b2af2bd6d absorption_res_37.out +c863a6795c58fbbffb2e62638d33e332 absorption_res_38.out +5f0ed9de13a657df45fc9ca6c392356d absorption_res_39.out +08c1f9ce81f77e24dd21b2d26c5532c0 absorption_res_40.out +3867ea1b27d523bec6340078954c054a absorption_res_41.out +47821386ad142d160f73a331258a3a7f absorption_res_42.out +9d54a224910c28b8a9790a29ee0d32b7 absorption_res_43.out +8a5f41fd362cbe2a5fe74ea21b97a4ed absorption_res_44.out +8e419f0d0f8bb85690061eff2d7a99f3 absorption_res_45.out +6094091433f4ef01280f4e674d102ab5 absorption_res_46.out +553a02e4b07881215c71ca9ae5df1bcf absorption_res_47.out +b665c6ccd4e1bfdc485c493c5a69d8e7 absorption_res_48.out +601a79c155fd99aa8f54717a35027ee0 absorption_res_49.out +e3855e1b30ad6a6839570b04b461e2fb absorption_res_50.out +edf4f26405eef6e983094cb4d0f28f9f absorption_res_51.out +e6cf8b29a7c0daf3d952c5335ca313e5 absorption_res_52.out +5abb58266b57568aaa262f1311e24ff1 absorption_res_53.out +126a67436744d573702fd79cbad03742 absorption_res_54.out +9ec726c9e9845fc4296b2197a8eb5eb4 absorption_res_55.out +260180c3dd22ad59024f4cbd71a7e10c absorption_res_56.out +3bf14bca1d14480dea13d2eafae326fd absorption_res_57.out +5cb01670b586b60317eff53bdce43a11 absorption_res_58.out +1aa40ffa5828c3d5518fed0a4844dad9 absorption_res_59.out +d5e0e5ea6c975a8d5841fc729afe6021 absorption_res_60.out +4f68e3bc450e5938ba4b4ba5f1283a5f absorption_res_61.out +8cf855afa17bc57cd1eb5011eb68a4b5 absorption_res_62.out +2bfe3521ad5ea7ae289a69f2afbacf05 absorption_res_63.out +79852db1116f87142f1d3cf60e43a9ea absorption_res_64.out +d2dfe4e3b15e7511bc82ee56ebb5063c absorption_res_65.out +8125b204f0ad8a1d1da8c5b4a23e554a absorption_res_66.out +ae76825555a38ea699ca66f3dac9a95d absorption_res_67.out +c2f5d37ef88e99ed3a9cae7b47930129 absorption_res_68.out +4ca8017dc272ba27b90ff74f75dd26d6 absorption_res_69.out +4647dc4beffbb57093b2745ce09cf804 absorption_res_70.out +8c56950777f72d57635ce8dbcbea880d absorption_res_71.out +f7c4c61e1909ca184279118e4725b53d absorption_res_72.out +e5651b5418753051a8c3add6c287e0c7 absorption_res_73.out +1ae8a64df9f21f9b0ef11d3afd98f52b absorption_res_74.out +5ca20c09371c4b4b88bd591e071cd489 absorption_res_75.out +1a03555b6a90a24a50585286e83d74da absorption_res_76.out +a37b4e8585e8dd8b83097b3beccec80b absorption_res_77.out +43730fdafb99f80dbf06fefdaedfdaaa absorption_res_78.out +f0ffd194857d86adbec59135aab904d0 absorption_res_79.out +89730d54a7184cde2375fa118993c3c3 absorption_res_80.out +8bc5217888ca0548c77318af2a68682d absorption_res_81.out +b9bd72bf798abca4189a8a3acf2c3cdb absorption_res_82.out +0671cdbd7b3dbcce8b21de58b78da2d0 absorption_res_83.out +a4f6004493ae4726cc6b6a18b41698d0 absorption_res_84.out +7fef4ccfa29a7d51f427cdfca67a0889 absorption_res_85.out +2dddad5738f05cc4c45b2915ed0f84b3 absorption_res_86.out +de94e8378e03baad1bf3486740d0881b absorption_res_87.out +b9260ddfe75c92ad369e9c6cec6310c9 absorption_res_88.out +0c48b13692a83061f45d3a1a93605bc6 absorption_res_89.out +d55d2c22a3f1761c848a38e5004bd8aa absorption_res_90.out +7d0bbc042dbabf3b93f2254402aefe5f absorption_res_91.out +b6750b24fc391795e031c3dbeb5d62e4 absorption_res_92.out +2a4f247325ecb8eb670d60bed18cc93c absorption_res_93.out +e5bdccfa7442c8ca766baf40d031e826 absorption_res_94.out +d4ead14a5547c95ae76056bb4e95c0d4 absorption_res_95.out +dce382446e007af2b1677befd0a7f9ea absorption_res_96.out +97e8addb338b5ec7b4767d22e075ed29 absorption_res_97.out +3f44b670ea956597b7bdf2c88aef05cf absorption_res_98.out +bda971ef712f64ae3b72422fe39015a7 absorption_res_99.out +f9bb214eb7f1ac22791a13c8025c4887 bflist.out +f8ca9ed9a5caf8ae8998c83481372483 deposition.out +4d34b34173e2af0bc6977fd30f3d69a7 emission.out +a14f6a7fdc0f7455be5d0c944e94e007 emission_res_00.out +4b6dabd6f73562507c0b402e4ab25d6a emission_res_01.out +0f55630f2c73b8e22b7a3c9d1d616d9a emission_res_02.out +2061a1c3405a132eb05bd86ef76eecdc emission_res_03.out +085e5a078a4853291ab86e54250e49a7 emission_res_04.out +04aff0f30aa1a3d2a3acd32114272d69 emission_res_05.out +1180715998441158cfda9e787e3b4ae0 emission_res_06.out +47748e274a5c8cb9039a125b1dca7cbe emission_res_07.out +121d76da8acdb96efc9e84db78751905 emission_res_08.out +db8b61dc33665fe27628a35e230c5891 emission_res_09.out +54c45923b01110ee091832b0afebf400 emission_res_10.out +0b23cd17b2fef9b7f30ec621a664caea emission_res_11.out +40ba79579724845ebf4d6a36935d9432 emission_res_12.out +a0bfd8450c72a3863fbcb09b234f59b6 emission_res_13.out +8a7ad5de253716ac457c27b68b90ca0e emission_res_14.out +cef6efd72cdd743a1f50783d0df64cce emission_res_15.out +ea59e6fc6572e2762fca4f11357cee29 emission_res_16.out +1b21af8d31ce00e0451ff8254fbe419b emission_res_17.out +1d7fa97ce27b1a2ef1ba5e718f6d5303 emission_res_18.out +44925e969694bc6dc7ad7a1eb454acba emission_res_19.out +61443c798a707a9a2d4ac7cd4a5867c6 emission_res_20.out +7bdc8461d6047ff0e7c418ec0bafe9a1 emission_res_21.out +f22b6e06a247f06fe8e637c4defe80f5 emission_res_22.out +0599815780decfa6d4be0cfe12f85f54 emission_res_23.out +2270cae2bf5885b7dd2fffc272767d02 emission_res_24.out +bf7c69dd7ef649bf6045e2eb44596583 emission_res_25.out +ee8a7f8447bddbba5b54b15e72721514 emission_res_26.out +cc838c443c61d2a1dbb2cb7a3f70039b emission_res_27.out +ac7f364bc03b5ae55a2612884288519f emission_res_28.out +d679284cf19c2f9319a330d21e9e9c02 emission_res_29.out +63a90c59746247183922360d2ec2ca03 emission_res_30.out +ebaf9335b10990a1d59976438d434468 emission_res_31.out +b99db2296cf5a7d44ac17e777ad7d6e9 emission_res_32.out +92ce138de44a6a5aa0147256ba28f5b1 emission_res_33.out +40ca9ea517667ebfe828a803891ee702 emission_res_34.out +fab94072c3e6cdd733204cf03c3e942d emission_res_35.out +bba28ad75f42531d6656202cd6dd8fa3 emission_res_36.out +6c8be26a997c359d76c543e5c2b1e636 emission_res_37.out +f5ba6d6aa3a5312bdde1acf90080c9ca emission_res_38.out +439e2d58531d8d808a327c0b8e9377be emission_res_39.out +24d390c2802d79e0f1ee0513dcffc83f emission_res_40.out +5c7b74e71254b7941c81af95a57803cf emission_res_41.out +b7b59d27d06c3eb7cbc7dc45c9307cb6 emission_res_42.out +bcbfe78312281075cc19e7cc73dd6526 emission_res_43.out +24cfc3a625f8a750e1125fcdc52f6732 emission_res_44.out +309c3fb61e3d0486d6139e556d56a49a emission_res_45.out +68855018ef3cd36c3d54361859f3d60f emission_res_46.out +00d97b47ef5185c67e58667ee7c11397 emission_res_47.out +0e957a32d929eb96dcf9eb25b7cf40ee emission_res_48.out +9cbb2bef88e5c9c4f65c482485643fbd emission_res_49.out +d1230f0ffdd1e9dfd4a1cff961026e76 emission_res_50.out +6c219469985af735dda6280995eccd00 emission_res_51.out +08623bd829d7f5f0ec655fa010b7c957 emission_res_52.out +5fe95022445cd516d54ff0def4bfdfa1 emission_res_53.out +92c92b17a265d538a25bfac137099211 emission_res_54.out +b3188dcf3221fc3b62debf08a93ddef7 emission_res_55.out +cfff0b78ce32bcb384c104bd46e1c497 emission_res_56.out +59afaa4afbba03ee6ca9da2c2360141f emission_res_57.out +16a9831d7a0d33cca15807ac57967895 emission_res_58.out +e9772141601f69172170f9e230ff1466 emission_res_59.out +42836da4e3078cddb085d963893b796e emission_res_60.out +b6bb918a4f6ccfaaac4a967bbedb99be emission_res_61.out +92ea2c4ad0d98d901f0ee39abe32b371 emission_res_62.out +921605be21c6040ee49fd9865d301952 emission_res_63.out +2d1ba9b0de9d118aeab560bf1bbfa0fb emission_res_64.out +97b8db0bb0fce240b3c3ad7272120278 emission_res_65.out +e792cb53f9cd694dfc5d9ddd204a8646 emission_res_66.out +d7abefb41b338d5683ad2ad0a4c15d0b emission_res_67.out +e09a618c9d6c93e0aa432e60f6cc300b emission_res_68.out +e3cf19703db6699a4793900cb9e6cf4b emission_res_69.out +93dcb788e0738d293ba4b30dca28e786 emission_res_70.out +39ec6e4772a0a7c6cebffb26c1d10d5f emission_res_71.out +0e22e395a267a9075a47d0561e0bd7e4 emission_res_72.out +880b1908b73777fed72a998a6c048684 emission_res_73.out +4e0fcfb6a3e9c7192fa8bb477a11bbc4 emission_res_74.out +28b03b28d91efcd44d80519142709f0b emission_res_75.out +4fe0119e54e3ec898987f24e8a86f707 emission_res_76.out +7250957ddba6f286c8a71cbd402eb5bb emission_res_77.out +81c82aabb9e47d847bb4c3b9ab53023f emission_res_78.out +5876a33cde6290187b1c472b470cb14a emission_res_79.out +c9fe9ed6f96b1898c1554bd2375242e9 emission_res_80.out +55f9e21d18974016a36fbae0896ad3e5 emission_res_81.out +40dba19dc2f7d146b87b245b0bf5988b emission_res_82.out +e30f52f225c81d9e1c29b64428d06d49 emission_res_83.out +1a0781cd9ba61cf7e83a7eafe2462b6d emission_res_84.out +83ecf20fbd661159bec4138702a686d8 emission_res_85.out +7b14429d289b78c7d077068390d63f8f emission_res_86.out +65e4eda46de37e79015c1edac96611e1 emission_res_87.out +003ab4a54fb4de5cd0d9dcd70e249a37 emission_res_88.out +192e208d0cb51ebcf8d7d48eb9e1a76d emission_res_89.out +5356a14a6305788963b24789cc10e82f emission_res_90.out +7abb009aa52a6c5d4fef75fb9a297f27 emission_res_91.out +4929bd542dd5675e821385afa35e5837 emission_res_92.out +19a0108b505eb27497c2a39283651faf emission_res_93.out +975fc8a452adbe099d98df7ef016ac4e emission_res_94.out +23e8760ca9a5b3af979d3278572d021f emission_res_95.out +0518a92d33dfba8bc83fbe2886ba3951 emission_res_96.out +e1179985be4aae1c580b04b11c9afcfa emission_res_97.out +9b9e2dc6309f75c15ba9f0003cb5f089 emission_res_98.out +a07eb663c700bc1917a38a201f29bb64 emission_res_99.out +6ed758f6fbe331256584bb618a624820 emissiontrue.out +0fc9420a229d156f425fc02ab4df3393 emissiontrue_res_00.out +631995765c2c510f201b98ff7ca2ccc8 emissiontrue_res_01.out +01a8373f8b3ed8230643d5eb81945b92 emissiontrue_res_02.out +567f24e8f8d6444d487f0e8ba8f7dd02 emissiontrue_res_03.out +0d79c51219b24a903bce440c655e96a7 emissiontrue_res_04.out +43c03f02efc83f284d473ce1cfa54ea1 emissiontrue_res_05.out +c7226c53710dbc04a61efdcc82a77d29 emissiontrue_res_06.out +6acb1c14358831745e114671967c7399 emissiontrue_res_07.out +09d0fde719c14a09e34c50acc5d337e8 emissiontrue_res_08.out +f7a2e5f779a9b7b863f8c0803d0a944a emissiontrue_res_09.out +c9b64ccbfb4dcda5828c5c7138d9f2e5 emissiontrue_res_10.out +75c679fb178e4919295031b061c58db9 emissiontrue_res_11.out +f2912410b16d1baeb32036e4c22c18ad emissiontrue_res_12.out +a9635e1a162de0f7f1942f6726f53373 emissiontrue_res_13.out +788fa241258dc4a0a6455082b3ce90c1 emissiontrue_res_14.out +25a2b628b33527a7181eb7c2a7cd9851 emissiontrue_res_15.out +2323c0d674c18a1ea10937425214bbfc emissiontrue_res_16.out +88411722abc921c7d206969bd3edc6c7 emissiontrue_res_17.out +75d4773ba25f85dabc5b02fa7feb4880 emissiontrue_res_18.out +70d5ea4d03edcd1c841a2849981c38d3 emissiontrue_res_19.out +7d165a3e8476cbd47a619b43494b33b4 emissiontrue_res_20.out +558fb03379fe86fa86fd5964d8af7a77 emissiontrue_res_21.out +1f5ff42c571a846f7dbd4b5a4f34042f emissiontrue_res_22.out +91c1758697bf2937ebc63317936fe035 emissiontrue_res_23.out +736dbc093ea3312e7ceab32c611fbc28 emissiontrue_res_24.out +0177a4b2bf0cff947ce802d1e977d005 emissiontrue_res_25.out +3ecfa6926e5129e2c686ca84e0cfbc81 emissiontrue_res_26.out +7bf8ed3dc49db5b9d4a76386b9fd99fb emissiontrue_res_27.out +70b4ed0cc23ed2af13723e5caea724aa emissiontrue_res_28.out +25c7ef5d661284ca48bb41b6a2a69a63 emissiontrue_res_29.out +06a3fb2d91d984d84734137794c42f44 emissiontrue_res_30.out +86a0670664a50621cc956e424b97950a emissiontrue_res_31.out +117487afdefdf17a8a7551ac5976ae47 emissiontrue_res_32.out +1d5448e43eb87491e4ebfb54eced80a0 emissiontrue_res_33.out +4063562dc248fe77ee69f17096427ea6 emissiontrue_res_34.out +77c205e817b5e20a4f933f5882b5a6f0 emissiontrue_res_35.out +1734f4794ee5f549a1497c6d5a10b419 emissiontrue_res_36.out +84ac6925d36a581daaecefee81803113 emissiontrue_res_37.out +7bd68e60f7c4b27c37dc6de8c3101df6 emissiontrue_res_38.out +61b47309c41dae4b7294c26a84937d1c emissiontrue_res_39.out +936c79de77734132c36a95190cef39a5 emissiontrue_res_40.out +7b66d85f4d3d6d2e70aebb7c78c75a46 emissiontrue_res_41.out +39f4de2332c9a1646d57ae74a90402f1 emissiontrue_res_42.out +0c292420b15973ee6e43bf4c07557d0b emissiontrue_res_43.out +32b99254dbaef7149be95db076bc9b59 emissiontrue_res_44.out +3ebe71af8109d86d1fd3b51d406f772c emissiontrue_res_45.out +f4d5ed3e4a4c8eb660b9e8c70453cc0f emissiontrue_res_46.out +fa37ca3ced0dd1028c16d298b9ca3c39 emissiontrue_res_47.out +1270a176ad061d45e034466ef7d0d0e1 emissiontrue_res_48.out +801d865f8f5cb85446f81b9a8f668471 emissiontrue_res_49.out +1de729e08d0d04bb821189a5e4574e0f emissiontrue_res_50.out +5ab0f3401d0bf2289484fa93ba2e51bc emissiontrue_res_51.out +578a86b5b4b1082af2e6a399b219c2bf emissiontrue_res_52.out +ced6e2b40b6bc5dcbdf0fad825506cf4 emissiontrue_res_53.out +ca09e35d263592fa6fd94e23d19f9750 emissiontrue_res_54.out +f8c593c9b291fb3678b96b3e840d58bf emissiontrue_res_55.out +16a76959e29d9b5088484eaa554fd1b4 emissiontrue_res_56.out +393a824f334c03442904b60e6011df7f emissiontrue_res_57.out +87ae89678046e4d69b063d438bdef6a7 emissiontrue_res_58.out +c41fa2f80e71a90d4d59cdd9778babc9 emissiontrue_res_59.out +b045331d8d0d2535429f82e34d145100 emissiontrue_res_60.out +38fd36211500e98322f76663217c893c emissiontrue_res_61.out +e03e597cbd21846003ca2c5158b49cd5 emissiontrue_res_62.out +0712634195d7a5c64b786bf83f0dd864 emissiontrue_res_63.out +03c7c92105d90ecfc12176157e9c3228 emissiontrue_res_64.out +aa2887c62de648b9eb25a0fa21380ef6 emissiontrue_res_65.out +6951878df21e5682e2a10dd80303ff4f emissiontrue_res_66.out +25f19a03f988a3195410fb95777429d4 emissiontrue_res_67.out +f2720dd7fab4a9b908edc999ef3c1e58 emissiontrue_res_68.out +6336fd33314c78f7d1de5a0b2d83be30 emissiontrue_res_69.out +4e69c3e07be73d3c2bf782bf1ce85c48 emissiontrue_res_70.out +eab2f2eb43c4d0486e2dcc91142a6db2 emissiontrue_res_71.out +631c9cffa0ddbb2b55c0a425d0683109 emissiontrue_res_72.out +067aab91e49679a7fbb6b96fa2bda172 emissiontrue_res_73.out +82071418f1b7aba7815934d8ce379488 emissiontrue_res_74.out +ad8fb23b024931b99970e21b3f07d4fb emissiontrue_res_75.out +123190ff1553515a9a6572dd50536e54 emissiontrue_res_76.out +0e659baa137c2b273dd9bee55d49720d emissiontrue_res_77.out +307e0d4f8704f425762e28f92c9dabe7 emissiontrue_res_78.out +0484aa23ac88af69993e706d9b33f320 emissiontrue_res_79.out +04858401407bef0a009edb42be7dfd0a emissiontrue_res_80.out +086de8390270e7795fb7187d91f7e7bb emissiontrue_res_81.out +5ba2dd543a3175b3ad3ed049f2f5199f emissiontrue_res_82.out +e698ef10fbe48fb61d1c925ed862a371 emissiontrue_res_83.out +720f406966767d54c5a1c53f6b9ed13c emissiontrue_res_84.out +f532f26112e4e794eb345bc08158198c emissiontrue_res_85.out +7fefc72d23f83a6716ab46418d98b5a7 emissiontrue_res_86.out +fb41872c4eed81512d736b40391ea493 emissiontrue_res_87.out +cbf2f11164217e84f5ed3a94c8152ee8 emissiontrue_res_88.out +b839a3e36daaac426239ee3478c1e01c emissiontrue_res_89.out +0575ddfc84a09d051bc90cb67f4e289f emissiontrue_res_90.out +4df20b8eae53b779be07eae598ea5fa1 emissiontrue_res_91.out +75d4e59cb9a59a67fa2dd4bc0ad3bd0c emissiontrue_res_92.out +1855b09a3ff188eb0bc8e59e1311cebd emissiontrue_res_93.out +79a34ef2513a8c79ad879a4d76a939b8 emissiontrue_res_94.out +e206e98f8f8dfe959caecf570de928d5 emissiontrue_res_95.out +49ed91ae21377f6fe7ce1b9c1fb42fde emissiontrue_res_96.out +1eae0999c578acce094357c92b822c15 emissiontrue_res_97.out +2c5c8b7e9c91c9f7a5502841732bb00a emissiontrue_res_98.out +88e590f4cc18310826be892b5f5a9a8d emissiontrue_res_99.out +5f291ebeb25086a65078dcb92eec856e gamma_light_curve.out +0476f6c2a1e0023cf76bc16a0b087062 gamma_spec.out +2b769145664780d4f90b07f963588536 gammalinelist.out +29ac1cb06f3139df7cbca0bbdb426e1c grid.out +589c74808ee61acc4d79bb4f84118992 light_curve.out +22c46f471ef3c2e126c8d4f37980f117 light_curve_res.out +9773becefdfe4afffb041b703210c67c linestat.out +fa80b4c76909e5984e9f17d0548a9a73 modelgridrankassignments.out +a1c91f6d89797e1feaf21d4d6186545d packets00_0000.out +2a64c187ff3d5c4cda87068966083983 packets00_0001.out +6de6558232711b33cd042ab495c496ca spec.out +0dd442806e68ef09fb6b1d1f6b4a98ff spec_res.out +a351f1711fecd60c023d0ba7332092db timesteps.out +ade51ef62b573258ac4974bbea28f39f job1/estimators_0000.out +cead8ecae6e4fbeeb9f49b1824176379 job1/estimators_0001.out diff --git a/tests/kilonova_2d_2dgrid_inputfiles/results_md5_job0.txt b/tests/kilonova_2d_2dgrid_inputfiles/results_md5_job0.txt new file mode 100644 index 000000000..456097991 --- /dev/null +++ b/tests/kilonova_2d_2dgrid_inputfiles/results_md5_job0.txt @@ -0,0 +1,14 @@ +f9bb214eb7f1ac22791a13c8025c4887 bflist.out +46149fb7fc6818ce05bbb5b4d6eefb34 deposition.out +7889f292c402838a73222e614531d1c1 gamma_light_curve.out +2b769145664780d4f90b07f963588536 gammalinelist.out +29ac1cb06f3139df7cbca0bbdb426e1c grid.out +3db3e2413ea1e67b4bb119eed503ff84 light_curve.out +9773becefdfe4afffb041b703210c67c linestat.out +fa80b4c76909e5984e9f17d0548a9a73 modelgridrankassignments.out +8f36691a42745261ce309bbac0599a53 packets00_0000.out +bd4a751fc9d0dc1c7fe7f60865b41a71 packets00_0001.out +600fc00772d3c1ad16948b6332791a9a spec.out +a351f1711fecd60c023d0ba7332092db timesteps.out +5ce4fd7564baff28fdc53625e53a83b1 job0/estimators_0000.out +85a8cb83f6ae8bb6594abdfa7ccd060c job0/estimators_0001.out diff --git a/tests/kilonova_2d_3dgrid_inputfiles/abundances.txt.xz b/tests/kilonova_2d_3dgrid_inputfiles/abundances.txt.xz new file mode 100644 index 0000000000000000000000000000000000000000..e4fa0e2fd58c51c30675b548a598b8b22596a41b GIT binary patch literal 48296 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 z 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 literal 0 HcmV?d00001 diff --git a/tests/kilonova_2d_3dgrid_inputfiles/input-newrun.txt b/tests/kilonova_2d_3dgrid_inputfiles/input-newrun.txt new file mode 100644 index 000000000..e4b815b58 --- /dev/null +++ b/tests/kilonova_2d_3dgrid_inputfiles/input-newrun.txt @@ -0,0 +1,24 @@ +1281360349 # pre_zseed: specific random number seed if > 0 or random if negative +20 # globals::ntimesteps: number of timesteps +000 009 # timestep_start timestep_finish: number of start and end time step +0.4 010 # tmin_days tmax_days: start and end times [day] +1.33 1.330000001 # nusyn_min_mev nusyn_max_mev: lowest and highest frequency to synthesise [MeV] +80 # nsyn_time: number of times for synthesis +3. 0.037 # start and end times for synthesis +2 # model_type: number of dimensions (1, 2, or 3) +4 # compute r-light curve (1: no estimators, 2: thin cells, 3: thick cells, 4: gamma-ray heating) +1 # n_out_it: UNUSED number of iterations +1.0 # CLIGHT/CLIGHT: change speed of light by some factor +-1 # use grey opacity for gammas? +0 0 1 # syn_dir: x, y, and z components of unit vector (will be normalised after input or randomised if zero length) +4 # opacity_case: opacity choice +1.0e-10 # rho_crit_para: free parameter for calculation of rho_crit +-1 # UNUSED debug_packet: (>=0: activate debug output for packet id, <0: ignore) +0 # simulation_continued_from_saved: (0: start new simulation, 1: continue from gridsave and packets files) +1e-6 # UNUSED rfcut_angstroms: wavelength (in Angstroms) at which the parameterisation of the radiation field switches from the nebular approximation to LTE. +999 # num_lte_timesteps +0.0 5 # cell_is_optically_thick num_grey_timesteps +-1 # UNUSED max_bf_continua: (>0: max bound-free continua per ion, <0 unlimited) +2 # nprocs_exspec: extract spectra for n MPI tasks +1 # do_emission_res: Extract line-of-sight dependent information of last emission for spectrum_res (1: yes, 2: no) +0.001 1000 # kpktdiffusion_timescale n_kpktdiffusion_timesteps: kpkts diffuse x of a time step's length for the first y time steps diff --git a/tests/kilonova_2d_3dgrid_inputfiles/input-resume.txt b/tests/kilonova_2d_3dgrid_inputfiles/input-resume.txt new file mode 100644 index 000000000..8f4486546 --- /dev/null +++ b/tests/kilonova_2d_3dgrid_inputfiles/input-resume.txt @@ -0,0 +1,24 @@ +1281360349 # pre_zseed: specific random number seed if > 0 or random if negative +20 # globals::ntimesteps: number of timesteps +008 020 # timestep_start timestep_finish: number of start and end time step +0.4 010 # tmin_days tmax_days: start and end times [day] +1.33 1.330000001 # nusyn_min_mev nusyn_max_mev: lowest and highest frequency to synthesise [MeV] +80 # nsyn_time: number of times for synthesis +3. 0.037 # start and end times for synthesis +2 # model_type: number of dimensions (1, 2, or 3) +4 # compute r-light curve (1: no estimators, 2: thin cells, 3: thick cells, 4: gamma-ray heating) +1 # n_out_it: UNUSED number of iterations +1.0 # CLIGHT/CLIGHT: change speed of light by some factor +-1 # use grey opacity for gammas? +0 0 1 # syn_dir: x, y, and z components of unit vector (will be normalised after input or randomised if zero length) +4 # opacity_case: opacity choice +1.0e-10 # rho_crit_para: free parameter for calculation of rho_crit +-1 # UNUSED debug_packet: (>=0: activate debug output for packet id, <0: ignore) +1 # simulation_continued_from_saved: (0: start new simulation, 1: continue from gridsave and packets files) +1e-6 # UNUSED rfcut_angstroms: wavelength (in Angstroms) at which the parameterisation of the radiation field switches from the nebular approximation to LTE. +999 # num_lte_timesteps +0.0 5 # cell_is_optically_thick num_grey_timesteps +-1 # UNUSED max_bf_continua: (>0: max bound-free continua per ion, <0 unlimited) +2 # nprocs_exspec: extract spectra for n MPI tasks +1 # do_emission_res: Extract line-of-sight dependent information of last emission for spectrum_res (1: yes, 2: no) +0.001 1000 # kpktdiffusion_timescale n_kpktdiffusion_timesteps: kpkts diffuse x of a time step's length for the first y time steps diff --git a/tests/kilonova_2d_3dgrid_inputfiles/model.txt.xz b/tests/kilonova_2d_3dgrid_inputfiles/model.txt.xz new file mode 100644 index 0000000000000000000000000000000000000000..0bf6e602673ed5ea09d20cf5d5fa60751a829dc9 GIT binary patch literal 655352 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

EinyeA6oY7AtV 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

    tc1%wiHf2HM#yq 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 z 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 z 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
      `|N( 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 literal 0 HcmV?d00001 diff --git a/tests/kilonova_2d_3dgrid_inputfiles/results_md5_final.txt b/tests/kilonova_2d_3dgrid_inputfiles/results_md5_final.txt new file mode 100644 index 000000000..dcc5c4250 --- /dev/null +++ b/tests/kilonova_2d_3dgrid_inputfiles/results_md5_final.txt @@ -0,0 +1,320 @@ +58e9480e053988088961a3515f58bab7 absorption.out +14639376503c2be22e164cf18a19c771 absorption_res_00.out +14f1290468979ef6f7c43115bbd61651 absorption_res_01.out +175160a10bed89fb0a0a7abe48442aa0 absorption_res_02.out +a1384044ae233b8ab92453adf5e0cf0a absorption_res_03.out +de6d190ec62b49e9fb3c68342a89a123 absorption_res_04.out +0bfa119d18b062dad3561fba074b656c absorption_res_05.out +634cb5d42fc23a68e889e7223bd20fff absorption_res_06.out +eeb6e1f0d7cf5bc76bc4ba759c041ab0 absorption_res_07.out +9ed91c5d8998c8a260133467ffe34f61 absorption_res_08.out +86ac8ee4f49b72f8ae5f0d286e0f898d absorption_res_09.out +6dd0d324ecb5f64fba5ab0b933d34862 absorption_res_10.out +7bcb36040d8928c0f705a9dad940d507 absorption_res_11.out +17976f6cb8896d73a540f5daffff9fef absorption_res_12.out +e1718f7a884902d78514c6c894808096 absorption_res_13.out +102121c27e797fb82f023868b6fd4a0b absorption_res_14.out +d0a6f4abca16da1fd7e54d014f44dce0 absorption_res_15.out +7972cd3c1f63bde17265014d043c37a3 absorption_res_16.out +c964e48ef99aad25003d0f4f560594bd absorption_res_17.out +6c09a398dca31588569aa4826984bf83 absorption_res_18.out +467b2ac792e5e33b7be1b6e7e3b20d9f absorption_res_19.out +1bb5f4a026abf31e7f981e7a6b88f95d absorption_res_20.out +918de21f9e3f28c1691f7ea7e20010e7 absorption_res_21.out +7d32b2c9603831fb97fe960cb6967a02 absorption_res_22.out +1c33fee201e59d9737c6d1a69c49ce30 absorption_res_23.out +8d7e2de6f87ae2411fdf3887c00c941c absorption_res_24.out +11cf40a11ab1a59b2da6395f25691e33 absorption_res_25.out +1f15bf1bd25c2a6699aef13d41de6189 absorption_res_26.out +966b8b4d011f72cf769dddbef3356932 absorption_res_27.out +66a8420f628d904f34b2129f433ff920 absorption_res_28.out +92d96250f433bf593a0b9fc682ed6d4c absorption_res_29.out +6def416a3c8a2807c9ab3c9c7d818ce2 absorption_res_30.out +11d996d26ef19c03a93cb4ed654506cd absorption_res_31.out +2061677c73785cc681af88634873111d absorption_res_32.out +774ed2382b2e34373e464e94f738f064 absorption_res_33.out +ecd13fe5ac5ce0be9bb1e500ad6e0063 absorption_res_34.out +912d1bea3c924cb3036b72e5de0765c7 absorption_res_35.out +0e45b17554ae270c601eeca1617ea16a absorption_res_36.out +7f3fdb1e9bb990d51c80e6a85fe31e88 absorption_res_37.out +980e73874740f298c8a5508dc384360e absorption_res_38.out +de5207d9a51f9967b4101c8e9105bc29 absorption_res_39.out +bcd9ba8b776b3e31e1408954cb17f529 absorption_res_40.out +ae37301d3a15a803152244ca196bc2a6 absorption_res_41.out +b70585a6c145eb351ca0f90b80fc655e absorption_res_42.out +4264ea4c3bd081420a74598446d49577 absorption_res_43.out +11352d19409f9dd09701fefa25b2bf18 absorption_res_44.out +9ab57ef0b10367b5c114f3098b76e549 absorption_res_45.out +da7f2a69c5730e71da15bf25e09c4256 absorption_res_46.out +e4d8e67f1588803d39b68c1b0ec2f8af absorption_res_47.out +977d302212393ef690ee2673e8144020 absorption_res_48.out +061f64ab5e84aa2682237da474b69a1e absorption_res_49.out +840d77835522fe5c57abd9e6ae0b9bef absorption_res_50.out +68a60fad9bc1e5976e374c70a74cf194 absorption_res_51.out +b60943a49414b1b6721ff95e22ba600e absorption_res_52.out +41c109af3f39b25a18b98fc768f75dd5 absorption_res_53.out +a1ee0695f98a4acb56bcfc20b133df6e absorption_res_54.out +0ae65d8e51db03b1b3e3c3c4967e02a1 absorption_res_55.out +4f22d69ad2c60b82a36178346de2e62b absorption_res_56.out +b0b708adad38dd14adff506ab9bc41fd absorption_res_57.out +8d468b8ab61a477bab4fe9393b522e31 absorption_res_58.out +572644fed92c10be4dd0586f1411c4b4 absorption_res_59.out +c1a9d28de9dc8529cdc93561cebde758 absorption_res_60.out +482d2aa99ad437c2a8b814e80556c223 absorption_res_61.out +36c68a6e7683afeb5692cd74cdfaf8ea absorption_res_62.out +4d6ab476ee1f016fa4cc3da93e95a4e4 absorption_res_63.out +fa50e595024976caef963dddf36ce1df absorption_res_64.out +08beca90a5be687c763a84989b28981c absorption_res_65.out +a9b21544e928bceed396f6b1c10650ec absorption_res_66.out +8ccfefa5c5531c32658fa5e1cb43da48 absorption_res_67.out +c8e4302a83631e3db686c751fd370406 absorption_res_68.out +21f7f6d61904139a5b74eb7fc2749653 absorption_res_69.out +51c946136cdc22e46db9f97aec34f4a9 absorption_res_70.out +c9ee01c8fecf28e78f29d37f4f39df06 absorption_res_71.out +9352e5e70a98c6414f57382b27647a83 absorption_res_72.out +c17ad04913547a1c03bd3bece161eeb9 absorption_res_73.out +6cf28a390172df5d71bf9c109de9265d absorption_res_74.out +d4402c1df468f35ca8428333c24f2ed7 absorption_res_75.out +5bc1d325ef44f204315925ed126dd71c absorption_res_76.out +ebc3fbdcc113c5fa579c5f404b9096a5 absorption_res_77.out +554cd8fc13404a10cea5ecb432918295 absorption_res_78.out +eb04cc66589af585cd8b3a48ed879703 absorption_res_79.out +b3c7247fe453b8479fd3a96074cd7fc5 absorption_res_80.out +f4255c8b3f82b670e0b8a75ad10195b7 absorption_res_81.out +19bee0943a4b80362d501c0932088eb4 absorption_res_82.out +1247ccba02f76e9f828b9e5758dcc4ae absorption_res_83.out +fb8efe22b502e12b1963c3172c1c8534 absorption_res_84.out +f3dbc89e8cdbe9e15ae64168368c7014 absorption_res_85.out +f0b6cc8477d83c40b88b70c3ea5958cf absorption_res_86.out +37086b3b6e3119b35bf5429e0abfef28 absorption_res_87.out +a8a1b153952d163fbc63b25fc30a6ce1 absorption_res_88.out +6fb2c2c67332c9c44ec7172a96c69e15 absorption_res_89.out +5aab4f7717c5b91ff004330b19719a98 absorption_res_90.out +feec8f38ba64438725b563b1128db3c4 absorption_res_91.out +1960ffdb11ff2272b2071296c1d10ccc absorption_res_92.out +12da524d35fd0587504c51c7efa76435 absorption_res_93.out +f9bdd89ecb781b9f6e6ceb5fbf1c0c99 absorption_res_94.out +422b2127a236811391d95246ae2807a9 absorption_res_95.out +4976c2033747eb367389e1de9dada10e absorption_res_96.out +870ef8fc41e47a3100b7c7109716ca16 absorption_res_97.out +57e456c0906dda812f6e416f389ccd40 absorption_res_98.out +86b3ba25e36c882fe42f8764ab07b6ce absorption_res_99.out +f9bb214eb7f1ac22791a13c8025c4887 bflist.out +8366d3ebcd1ea3ce5e2416970a367ce2 deposition.out +bc6fa560e008247eadb6689f5c8b9c1e emission.out +fce82ffc9c5e49124c218996f5a77eab emission_res_00.out +ec34daf448fc654db1481b08a13494c7 emission_res_01.out +5e732c0da50f9c9b2ee9e41ccd48ac6b emission_res_02.out +d182d702dea57483d68e699db5c59c65 emission_res_03.out +90d5b329836b3be080352c6fb3083b4d emission_res_04.out +574879b597f762e080dbc9a80e258f45 emission_res_05.out +32ebbbf131f2fef209432abeedca5113 emission_res_06.out +0d174cd8c91c7c9bab50ecaf4241d9ee emission_res_07.out +9ba008e957aa06ab08b2e7a53697dc57 emission_res_08.out +e13f3e0a033d662d50e6f6902fd8bab4 emission_res_09.out +32174ddb8b9247239c333d2a5153bed6 emission_res_10.out +fbe6eb3c7ace73b7e2b3053730a26894 emission_res_11.out +82e596bbd6501552d69edbd1fbbf6750 emission_res_12.out +b6fb3fbc20f1b1870d39333b043c11da emission_res_13.out +23400db6ab0d6e29988eb9033c752e2d emission_res_14.out +44dfc8ef21ee931cdb7f95e801f17288 emission_res_15.out +55d55fc01142af8847e19c71136d4a4d emission_res_16.out +d3a67ebd68f8e64ceed320078ae422a1 emission_res_17.out +0378cc68f87c55d209344decfc5aa6b4 emission_res_18.out +c05b1c1984de7500d3369ccfe745f430 emission_res_19.out +f1d206123f62bc9fba0cc7507a901133 emission_res_20.out +012d301a2393c787e9d5f4ab351f6767 emission_res_21.out +01115f45d00f6dc5b4ffcdf8c186c710 emission_res_22.out +6cad767f0c093e17d3615a949e6b37d5 emission_res_23.out +88fb7eac7db84d31d52b291500ec1ba5 emission_res_24.out +3e4c14189fba2fa2a21c3b403e0c9f0b emission_res_25.out +bef4bc26b0e7bf0be8525cee6e37a31d emission_res_26.out +20f19442caf5a30bc879045c7fca4619 emission_res_27.out +b9ddd0ec8b6082e51725d39ca8942637 emission_res_28.out +20f26f345e42d1ca5917ed0a765bd3cf emission_res_29.out +a0837c3a520004e2b85ff75247b8f320 emission_res_30.out +96995dd125537f275fd7273de02a13cf emission_res_31.out +8fae5da59c37fb81c2b2ab44b812232b emission_res_32.out +635dede103e0e190098b45465e9f067a emission_res_33.out +bd4d91e8e35d03c9ff7ce0ea4c12625d emission_res_34.out +908b9a7abe4f28748c6338d777eaa90b emission_res_35.out +e99982dc2f7d9ff4fa4ca565df36633c emission_res_36.out +bc374e42d7753340308e08df01b7a4ca emission_res_37.out +cb1fdb302296c869d439d24dc32e9fa4 emission_res_38.out +26ba0611b928b54933ed083d6c778151 emission_res_39.out +475058f982e0daa61d0709d060072457 emission_res_40.out +49684a63f9a5e58832dadf0750bd2e98 emission_res_41.out +c6599f7ca75dc08465774c4266d8fd75 emission_res_42.out +4c20340eabfa378daf2ce6d2b3564987 emission_res_43.out +49f0d219aaa042e5dd23774f1e435e01 emission_res_44.out +5c6ac3326b4b35ac81a0ad31e6611aa6 emission_res_45.out +b95e31006f6a86e361e4f2284af7c222 emission_res_46.out +14530a215b50ae1aa7a84c9c33e4daae emission_res_47.out +c4c37333cb99bfcc55d1902c08e19c7d emission_res_48.out +e9db55cd89c5d654f2447623e4ea4cdb emission_res_49.out +83b3ba3ba96e7404b284132fc267d874 emission_res_50.out +9c9562548e00e1bd43cb33bc854c8c66 emission_res_51.out +eea48b65bffe125c5422e3da2274d152 emission_res_52.out +2b364e1456873a7a53af1e97d8ae11d4 emission_res_53.out +4f1250860e40d49ff159f43f6b0471d4 emission_res_54.out +81031b5e0fafdd258dbe3b889205b51d emission_res_55.out +dc546e956e69b08cee6054c481ac14a1 emission_res_56.out +8ffb00857894c98bf2b55664d9dc9a96 emission_res_57.out +3dd96627af15d3acede122ff3d4010a0 emission_res_58.out +49425c5b3a2281ecbe58b7c2fb35c787 emission_res_59.out +128bf7f8db28f0b0f971a5ea6d918a20 emission_res_60.out +7a10eae1478bcec225b2ca9d1559b3ec emission_res_61.out +2d994dec7dc39870cdd5dd53a6192f61 emission_res_62.out +5b280549f790396c5f3e1fdbfdd12977 emission_res_63.out +d8e3f56e1b3facfe5379160c48a40a3c emission_res_64.out +11f5817d0d1b622265df247f19e08769 emission_res_65.out +84838084f87173b083ac52f414b0e825 emission_res_66.out +efa30532f34528809a9b8dd2882b8620 emission_res_67.out +cffe4531f4359e198e43cd3ce4adca65 emission_res_68.out +943a13f7116b02b719e3b2747ec70f98 emission_res_69.out +df777e2fb91a2ef22d607c0e0a975b8f emission_res_70.out +b0417f26cf40add951aca352957f4abb emission_res_71.out +d398191a21a1cb5b5c337ba0186b7e4a emission_res_72.out +eaecd4b10bedda7e9a790d13d4ab5634 emission_res_73.out +99ce389ce21a68899ce6dc791159b4af emission_res_74.out +950697bc1f9d777f7cba9c25480f2489 emission_res_75.out +b9d0792f746bc961e395119d259b93f7 emission_res_76.out +3a4ba51004b4540a884833e3ee393538 emission_res_77.out +276afa5d59d0a5b01a398d2e0ea59f15 emission_res_78.out +b738d1a6f422be8801d484724a159f91 emission_res_79.out +ed8eb65b7e44b84279f3f91a2c7fd460 emission_res_80.out +9d6b3dcc35982fc18e6eaa0c30b0374f emission_res_81.out +bd056e202e0625909db64f41218ca12b emission_res_82.out +b0b2ed9a3f1aee340442e4bced8f2ef3 emission_res_83.out +ed498b9e8ac1a841853da32fe775e1db emission_res_84.out +cd2a878386c9652456250abab80acf1c emission_res_85.out +23e0223f08c621f5438bb7cbb0483152 emission_res_86.out +051707b966ea8130cb9f392906d7bea1 emission_res_87.out +7bee63a0cb4f123224ec5abde90d42b4 emission_res_88.out +4542f32d07cf213726c26c19ee31c3dc emission_res_89.out +0301fdb39c96a8bd664b2f5647e2da85 emission_res_90.out +797985243f66da45812a85511bfd9f06 emission_res_91.out +6986946cf99e36026d3d157779e3e19a emission_res_92.out +ee26af93e3e7ca075927fb34134403fb emission_res_93.out +3ea932e91d60dbf2d278569a17148978 emission_res_94.out +b0c753216babe27b7b054296742ed135 emission_res_95.out +00129c83b8a5202b35f19c38ff5ddc45 emission_res_96.out +2c9422c76769c391010029dba3b465f5 emission_res_97.out +e869f8abadbd5e7b105ed70337ebb254 emission_res_98.out +08b5ec8e2503540a224065d615878102 emission_res_99.out +9c52452f8f3274a371265eefd9adc0ad emissiontrue.out +266ad84582cfe1925318cb59413a6220 emissiontrue_res_00.out +9d89f0586c7aef47c5bac932c5e097d0 emissiontrue_res_01.out +168be5dfefd0779c50ffb8f955d6a340 emissiontrue_res_02.out +dd3a9eb027a89cafdb78664e0333e37a emissiontrue_res_03.out +0dfde129876b447f0491184d482c1ab5 emissiontrue_res_04.out +d9c00947f33207153abbfd5132597ba6 emissiontrue_res_05.out +4c16b6b16760c157384aa58eec429704 emissiontrue_res_06.out +1523304ff88a8e06bdf621c0f02be023 emissiontrue_res_07.out +d114966820b6338df3a6c0114f4125ae emissiontrue_res_08.out +0a2fe2aa0366532296e83e9cd59cf01d emissiontrue_res_09.out +e28d09960c53b3190caf5f6b8d33f0e6 emissiontrue_res_10.out +30cf111f1421f4493f9801d190618f50 emissiontrue_res_11.out +9350f706d70258f3c6edd6863bb22376 emissiontrue_res_12.out +c77e3b53d4a49fe421bcefad19cf3943 emissiontrue_res_13.out +20ad1e7156facc46e284c6d5910b3119 emissiontrue_res_14.out +5a9ac54ddf5c12139024b9167e73cd0c emissiontrue_res_15.out +75bd573f42b0ef75d721fb886920d9ba emissiontrue_res_16.out +80adec711a1b6da985aaa23785182ad3 emissiontrue_res_17.out +e0434a2095b946673f0981c4c4f974a5 emissiontrue_res_18.out +72c4c0670f5c9b3ea9282b0ef525445a emissiontrue_res_19.out +7c1cc7943e94f3d37ae9d69ad5fea95a emissiontrue_res_20.out +62f67171618aa3bcf3157a733d9b6395 emissiontrue_res_21.out +f7a4e0b7f9fb79e25915acec63708cf6 emissiontrue_res_22.out +56e445d7a12090ba631fea751480c856 emissiontrue_res_23.out +1d14b52c618398250ab168bb9629609a emissiontrue_res_24.out +68335aba2af0de9166c7097ea4991b00 emissiontrue_res_25.out +eea5f1c7c7c8287909c586f24f3c3747 emissiontrue_res_26.out +3343494ed80c50e98a2163e93f70bdbf emissiontrue_res_27.out +bad265db35e75a14f90604951e881e49 emissiontrue_res_28.out +231345a1e4a007a6e0d3fab0f58b13cf emissiontrue_res_29.out +25d5076a933b79db79c0a4d2f30c7c7d emissiontrue_res_30.out +e11f598dc4c08aaa2998d8d7cbfd8272 emissiontrue_res_31.out +5626a9f30c209dbd8066435653baec63 emissiontrue_res_32.out +e8695c0214de1b7fe5945f196a0dedf9 emissiontrue_res_33.out +60e9aafe6b059450ce249d06a6497c6c emissiontrue_res_34.out +e09111ce9b76a603d371c94f4631d254 emissiontrue_res_35.out +af61ef53bf8316966a85b18514e1f41f emissiontrue_res_36.out +16d871a20cb891853e5008c48acad453 emissiontrue_res_37.out +01e0839ead63e7a6f17566f5954f1829 emissiontrue_res_38.out +0d52bc4960b0ba8de365aab0411177d3 emissiontrue_res_39.out +27b5c7a2a32cacd119e025fa9f52082a emissiontrue_res_40.out +ca5dde8db09898915a41bfcc6462e547 emissiontrue_res_41.out +99ac492f50644d8b32296f061bd75ae3 emissiontrue_res_42.out +049647e9f546ba6a7ae6649d58879372 emissiontrue_res_43.out +7a0ed70c1790023de378a8e3486a4145 emissiontrue_res_44.out +a0b6325d94d76aa15e1e836273a86150 emissiontrue_res_45.out +c4850b369d5fc1976ca63e2516de1d43 emissiontrue_res_46.out +fcfe5e6912c560b1d0eecd32c3310e90 emissiontrue_res_47.out +d0b5c9524343965d5d4f3af1d2b64fd2 emissiontrue_res_48.out +779841fa9d3b26bc83bf31a2cfae5f2d emissiontrue_res_49.out +03628847b35041881f829f6e004b7ead emissiontrue_res_50.out +9e0593a3ba28197c27a237986d957a05 emissiontrue_res_51.out +38c15405b36252799d48bc138e08a230 emissiontrue_res_52.out +5d3e54ac3fe0650bafb2ff5632d0c663 emissiontrue_res_53.out +07e0bf3f11004edf87f55c9dc47a230e emissiontrue_res_54.out +c7d5b63c3a66e81d6f67d05863d5336f emissiontrue_res_55.out +a23645be33c15d81035981121cdf513b emissiontrue_res_56.out +2b45c13a79f1b80e2fe185181d0feb93 emissiontrue_res_57.out +bd1da9de6c7082e25f616bea0ddf46f0 emissiontrue_res_58.out +922761f9a847f526e9a90244bc78e46b emissiontrue_res_59.out +43172d21553f6e88ad6bd1a6bc214ecc emissiontrue_res_60.out +4b14bc1cec45c1394dcb394c1e078d60 emissiontrue_res_61.out +1e262d5a8f59dacd6dd515621990929a emissiontrue_res_62.out +181fde6d37b8eeba181566c897c35d34 emissiontrue_res_63.out +191aa3eb03f228842022d4d22c109ee3 emissiontrue_res_64.out +0267c0ab76c4dff67bea6694740660d9 emissiontrue_res_65.out +329d7b730e16ad79e7aacf8f8fac99b8 emissiontrue_res_66.out +4727ef5cf2e11b968b7d254e43e50c64 emissiontrue_res_67.out +b91a60348dd5a0ef9f4e4843aaba0434 emissiontrue_res_68.out +7d31cd0710b10f9785e7aa9de4301df6 emissiontrue_res_69.out +e8dbc210afa65726cd96d26821730967 emissiontrue_res_70.out +2cae2c119835fc8fffa0402c42235e0a emissiontrue_res_71.out +414186c03c417034882100a2790b0289 emissiontrue_res_72.out +7940f85ec2103ea45cbf1fbf471eea6a emissiontrue_res_73.out +77cb913678c1dab259b89ef3bb07887a emissiontrue_res_74.out +9fb3049258cd8b4d4874a0e2789e7228 emissiontrue_res_75.out +2b6bbd278a8ecc8620575c50ad20ad49 emissiontrue_res_76.out +2a83cdd578e175e7ddb35a3c3ad1dbd5 emissiontrue_res_77.out +7fa4420371c20124bd2881967cf605b5 emissiontrue_res_78.out +4dc95ffbbda3cbd2f0e575085d6f067a emissiontrue_res_79.out +1a0fb75927c4215fd79125942b44ea7f emissiontrue_res_80.out +e5f17788de93fb55276ce657f11c3610 emissiontrue_res_81.out +216df8b6f64a7c37f54d5c4eb23de731 emissiontrue_res_82.out +6eda66161b45594b058162949c0a2afc emissiontrue_res_83.out +4d992234d115afbea51ee377737bce44 emissiontrue_res_84.out +b155694cce857196c3c6a47e326788c0 emissiontrue_res_85.out +325fb0a55db0f827f5ead014adba486b emissiontrue_res_86.out +6e9d11cec3b050353b1f952172598547 emissiontrue_res_87.out +c20006e19b09a6933d2e797acdebd53b emissiontrue_res_88.out +bf4886fa13bfbac78e68ad1f0bb92043 emissiontrue_res_89.out +a29843212383b49fef863c0ee42707b8 emissiontrue_res_90.out +097fb55d9a082e2f1aebf4645eaba329 emissiontrue_res_91.out +d8065be9755e8705dd0a7d731d6ef066 emissiontrue_res_92.out +55bfb71845a1026247780d2cd821e6f4 emissiontrue_res_93.out +05c8d128047eb6d0440ea16af9bf7f3c emissiontrue_res_94.out +855759f98e997f5947047e9a8b600628 emissiontrue_res_95.out +98cce02a0253f396dfc1ca04e2a677ff emissiontrue_res_96.out +e80877705736b18c03533e8a89f5b5fb emissiontrue_res_97.out +8e24c8a8463b9dd48e00e720cc00357b emissiontrue_res_98.out +cb3ba58ba4beb0a1071b2f975fe47b2e emissiontrue_res_99.out +82a585a5ca9ffcaff2ba7eb780265741 gamma_light_curve.out +d22f0480629cf543df9cbc58dca6cef1 gamma_spec.out +2b769145664780d4f90b07f963588536 gammalinelist.out +b72b67aae10074c2b0915aaad7d9ccbc grid.out +0a19c2e25fca1ae65278653adbee7c0d light_curve.out +d59673879699412cfe041953e4daa1e4 light_curve_res.out +9773becefdfe4afffb041b703210c67c linestat.out +fa80b4c76909e5984e9f17d0548a9a73 modelgridrankassignments.out +9e9ea5eb62a7f904d2d52ac2c797e307 packets00_0000.out +14bc4d02c97590b4c351604253126901 packets00_0001.out +f2bea0bcfa94e8edcc00ce440857aa26 spec.out +bd96aa33323c64e02bb6b901f304bfbb spec_res.out +a351f1711fecd60c023d0ba7332092db timesteps.out +ce0c00c2d37a2829bbc04f1860622864 job1/estimators_0000.out +a25884811cb9bcd68c7a342852de882c job1/estimators_0001.out diff --git a/tests/kilonova_2d_3dgrid_inputfiles/results_md5_job0.txt b/tests/kilonova_2d_3dgrid_inputfiles/results_md5_job0.txt new file mode 100644 index 000000000..be6e9d755 --- /dev/null +++ b/tests/kilonova_2d_3dgrid_inputfiles/results_md5_job0.txt @@ -0,0 +1,14 @@ +f9bb214eb7f1ac22791a13c8025c4887 bflist.out +a02f3e5c0c16eb848950fe775ee4caa8 deposition.out +ed035872d205ede8cbefb6f6e66db7fa gamma_light_curve.out +2b769145664780d4f90b07f963588536 gammalinelist.out +b72b67aae10074c2b0915aaad7d9ccbc grid.out +b2e8ee953967d6709099ad05be61b09f light_curve.out +9773becefdfe4afffb041b703210c67c linestat.out +fa80b4c76909e5984e9f17d0548a9a73 modelgridrankassignments.out +b435eb715747a70d3372b1cc98250065 packets00_0000.out +cfb5460a9316c79c660bf7d913ea8e08 packets00_0001.out +f8cfd141dfa301309bd0fba60c6f0c71 spec.out +a351f1711fecd60c023d0ba7332092db timesteps.out +b66700748a8a5585562388ebca38f851 job0/estimators_0000.out +566cb793642c4e4ac43b50de2d114193 job0/estimators_0001.out diff --git a/tests/nebularonezone_inputfiles/syn_dir.txt b/tests/kilonova_2d_3dgrid_inputfiles/syn_dir.txt similarity index 100% rename from tests/nebularonezone_inputfiles/syn_dir.txt rename to tests/kilonova_2d_3dgrid_inputfiles/syn_dir.txt diff --git a/tests/kilonova_inputfiles/results_md5_final.txt b/tests/kilonova_inputfiles/results_md5_final.txt deleted file mode 100644 index 8160fd31b..000000000 --- a/tests/kilonova_inputfiles/results_md5_final.txt +++ /dev/null @@ -1,18 +0,0 @@ -95542d77876e6f397ff600dd92fbd595 absorption.out -f9bb214eb7f1ac22791a13c8025c4887 bflist.out -0485f42bbf37d9f7e6f9a3b9469c3b94 deposition.out -2183c62679cc04a8a31e894ba59ec5e0 emission.out -89321348b06a320ff64a7ad2a7e7e3a2 emissiontrue.out -6eca8b3e749ecb29800ee24b637e179f gamma_light_curve.out -c842a494a2c00fc36c5d800adc22199e gamma_spec.out -65cc464631353798bfeb1827f4affcf5 gammalinelist.out -17cf657837d7df2969e3e1540b183cfe grid.out -f2491b46c120da8f361a7e5eb3ea9247 light_curve.out -9773becefdfe4afffb041b703210c67c linestat.out -f5b097e63480ea2b54bb88459f72b19a modelgridrankassignments.out -f956be3397e7e8b09c8a5124b7173463 packets00_0000.out -78039e41502f02132134293eab5a1339 packets00_0001.out -7a0ec83225121a619e57d9651966a8b6 spec.out -a351f1711fecd60c023d0ba7332092db timesteps.out -401299c99599a19eb47494add55e7d68 job1/estimators_0000.out -44083ed192c1572a164a693626d7a56e job1/estimators_0001.out \ No newline at end of file diff --git a/tests/kilonova_inputfiles/results_md5_job0.txt b/tests/kilonova_inputfiles/results_md5_job0.txt deleted file mode 100644 index 1a57c0ba2..000000000 --- a/tests/kilonova_inputfiles/results_md5_job0.txt +++ /dev/null @@ -1,17 +0,0 @@ -3ea8821bd59d38690ec6442441ae9a0b absorption.out -f9bb214eb7f1ac22791a13c8025c4887 bflist.out -0cdcde572e0cb8f0f30f28878f990583 deposition.out -c42703eaa62aadd9fe30487c69425607 emission.out -cf929c867784306d6397ebea060ea12d emissiontrue.out -3b638b4a9e710452fdb3c1312adcc305 gamma_light_curve.out -65cc464631353798bfeb1827f4affcf5 gammalinelist.out -17cf657837d7df2969e3e1540b183cfe grid.out -d7c45301f40ee6ffe51e734764e7dcf8 light_curve.out -9773becefdfe4afffb041b703210c67c linestat.out -f5b097e63480ea2b54bb88459f72b19a modelgridrankassignments.out -90cf4df88ba47decdb9e565ef7257948 packets00_0000.out -ae9a146145bb688157baa32f9735006d packets00_0001.out -daf767256c8cf00f49048d9ebbb59cd1 spec.out -a351f1711fecd60c023d0ba7332092db timesteps.out -c8341395a154b5efff56ac137660726a job0/estimators_0000.out -e538777e662703ca2bf377c45bd3dc25 job0/estimators_0001.out \ No newline at end of file diff --git a/tests/nebularonezone_inputfiles/abundances.txt b/tests/nebularonezone_1d_3dgrid_inputfiles/abundances.txt similarity index 100% rename from tests/nebularonezone_inputfiles/abundances.txt rename to tests/nebularonezone_1d_3dgrid_inputfiles/abundances.txt diff --git a/tests/nebularonezone_inputfiles/input-newrun.txt b/tests/nebularonezone_1d_3dgrid_inputfiles/input-newrun.txt similarity index 92% rename from tests/nebularonezone_inputfiles/input-newrun.txt rename to tests/nebularonezone_1d_3dgrid_inputfiles/input-newrun.txt index 0d91da4ff..7840a6b33 100644 --- a/tests/nebularonezone_inputfiles/input-newrun.txt +++ b/tests/nebularonezone_1d_3dgrid_inputfiles/input-newrun.txt @@ -1,6 +1,6 @@ 1281360349 # pre_zseed: specific random number seed if > 0 or random if negative -10 # globals::ntstep: number of timesteps -000 008 # itstep ftstep: number of start and end time step +10 # globals::ntimesteps: number of timesteps +000 008 # timestep_start timestep_finish: number of start and end time step 170 230 # tmin_days tmax_days: start and end times [day] 1.33 1.330000001 # nusyn_min_mev nusyn_max_mev: lowest and highest frequency to synthesise [MeV] 80 # nsyn_time: number of times for synthesis diff --git a/tests/nebularonezone_inputfiles/input-resume.txt b/tests/nebularonezone_1d_3dgrid_inputfiles/input-resume.txt similarity index 92% rename from tests/nebularonezone_inputfiles/input-resume.txt rename to tests/nebularonezone_1d_3dgrid_inputfiles/input-resume.txt index 2f52dc68d..de564696d 100644 --- a/tests/nebularonezone_inputfiles/input-resume.txt +++ b/tests/nebularonezone_1d_3dgrid_inputfiles/input-resume.txt @@ -1,6 +1,6 @@ 1281360349 # pre_zseed: specific random number seed if > 0 or random if negative -10 # globals::ntstep: number of timesteps -007 010 # itstep ftstep: number of start and end time step +10 # globals::ntimesteps: number of timesteps +007 010 # timestep_start timestep_finish: number of start and end time step 170 230 # tmin_days tmax_days: start and end times [day] 1.33 1.330000001 # nusyn_min_mev nusyn_max_mev: lowest and highest frequency to synthesise [MeV] 80 # nsyn_time: number of times for synthesis diff --git a/tests/nebularonezone_inputfiles/model.txt b/tests/nebularonezone_1d_3dgrid_inputfiles/model.txt similarity index 100% rename from tests/nebularonezone_inputfiles/model.txt rename to tests/nebularonezone_1d_3dgrid_inputfiles/model.txt diff --git a/tests/nebularonezone_inputfiles/recombrates.txt b/tests/nebularonezone_1d_3dgrid_inputfiles/recombrates.txt similarity index 100% rename from tests/nebularonezone_inputfiles/recombrates.txt rename to tests/nebularonezone_1d_3dgrid_inputfiles/recombrates.txt diff --git a/tests/nebularonezone_1d_3dgrid_inputfiles/results_md5_final.txt b/tests/nebularonezone_1d_3dgrid_inputfiles/results_md5_final.txt new file mode 100644 index 000000000..2fa661eb9 --- /dev/null +++ b/tests/nebularonezone_1d_3dgrid_inputfiles/results_md5_final.txt @@ -0,0 +1,20 @@ +77a8cefec72da8c0bcebdf4e04d2fcf5 absorption.out +aff44ecad68d986f04fcd6110331ba8b bflist.out +9cfd74fab2244cafd4bce62dc6fe2ad7 deposition.out +986056dc9a141a00e7b62e653b2b4f4b emission.out +8607d1185f06e29637171e28955097e1 emissiontrue.out +9aacf70462a00d805820041d07deaa02 gamma_light_curve.out +035228757b6e30f01ff6a04a6a94d364 gamma_spec.out +057b226c371f3819cba5e04bfea3d114 gammalinelist.out +47dd2e31cc98d5d1dda67520fb399429 grid.out +2c51d13a376994eb179c6e97d44f1dfd light_curve.out +9773becefdfe4afffb041b703210c67c linestat.out +98195ccb920b6831d137861c8c6cbfa7 modelgridrankassignments.out +69cfdb90203ff26d32e2de036f464ca9 packets00_0000.out +d50e7c53ed1d845a36909777fc06f2ca packets00_0001.out +7ff320b87eb952c5e24295c2e12a6258 spec.out +8e7163982f1aa938dc1505478b8c60d1 timesteps.out +463e7d1a82b94f8c0fa7083c1f9b59d7 job1/estimators_0000.out +231bdb48880172490892c64690cca72f job1/nlte_0000.out +1c4b1ccb2ea3bd56f3ef976e4dce870e job1/nonthermalspec_0000.out +8d2160b6b8c6c451d9531d7be7cb0243 job1/radfield_0000.out diff --git a/tests/nebularonezone_1d_3dgrid_inputfiles/results_md5_job0.txt b/tests/nebularonezone_1d_3dgrid_inputfiles/results_md5_job0.txt new file mode 100644 index 000000000..4650f303d --- /dev/null +++ b/tests/nebularonezone_1d_3dgrid_inputfiles/results_md5_job0.txt @@ -0,0 +1,19 @@ +f5e5d8fc1f4eb7d1d2e7624e6929954c absorption.out +aff44ecad68d986f04fcd6110331ba8b bflist.out +b1c057449d45d3eafc42a30c2530cb92 deposition.out +91195eb22d4b77ed93bfc5edc96fbd79 emission.out +6bdc6267ae27feab57a34c8a91f78c37 emissiontrue.out +59e10adcf5e9d1c05f935e5583ad9e1e gamma_light_curve.out +057b226c371f3819cba5e04bfea3d114 gammalinelist.out +47dd2e31cc98d5d1dda67520fb399429 grid.out +e0d00b6a32be200c5cf0e9962089c0f3 light_curve.out +9773becefdfe4afffb041b703210c67c linestat.out +98195ccb920b6831d137861c8c6cbfa7 modelgridrankassignments.out +b0599d01d7bfc71cc14e2fd2fe1bd313 packets00_0000.out +1b9e11a486b6bd9fb0171566fbe73c17 packets00_0001.out +65539a0900e70d998038852567575617 spec.out +8e7163982f1aa938dc1505478b8c60d1 timesteps.out +2a274951a4fff75b7962281cf7bd043c job0/estimators_0000.out +a0850c5580c2ac45a01fefccbc87c702 job0/nlte_0000.out +1c4b1ccb2ea3bd56f3ef976e4dce870e job0/nonthermalspec_0000.out +fc10e7d1fd915e9372566c536d9d4652 job0/radfield_0000.out diff --git a/tests/nebularonezone_1d_3dgrid_inputfiles/syn_dir.txt b/tests/nebularonezone_1d_3dgrid_inputfiles/syn_dir.txt new file mode 100644 index 000000000..ba4514071 --- /dev/null +++ b/tests/nebularonezone_1d_3dgrid_inputfiles/syn_dir.txt @@ -0,0 +1 @@ +0 0 1 \ No newline at end of file diff --git a/tests/nebularonezone_inputfiles/results_md5_final.txt b/tests/nebularonezone_inputfiles/results_md5_final.txt deleted file mode 100644 index c0c14590b..000000000 --- a/tests/nebularonezone_inputfiles/results_md5_final.txt +++ /dev/null @@ -1,20 +0,0 @@ -28a6c36df8d636f510d95bc7271264a1 absorption.out -aff44ecad68d986f04fcd6110331ba8b bflist.out -be0ea11b76c8a0c43d672708dc86eb04 deposition.out -8cc8f6b1e2f8677b8d06f8349275c68b emission.out -887876fedd289e1099430cf25d27a8e7 emissiontrue.out -795e15e87a5becce1de1f13d786102d5 gamma_light_curve.out -d921cc1ced74b4225da7789f1c5689fb gamma_spec.out -057b226c371f3819cba5e04bfea3d114 gammalinelist.out -47dd2e31cc98d5d1dda67520fb399429 grid.out -6897a578c2bc854aa3fe4430fcddc46f light_curve.out -9773becefdfe4afffb041b703210c67c linestat.out -98195ccb920b6831d137861c8c6cbfa7 modelgridrankassignments.out -8a27873ed010c86ef5a0025427e0f584 packets00_0000.out -ccfcf24ce1bbc44f6af4c3f5cfec3776 packets00_0001.out -6af813b991bd486cbb780e232fd45a25 spec.out -8e7163982f1aa938dc1505478b8c60d1 timesteps.out -c71682d68f654ac713d30d65d6859e68 job1/estimators_0000.out -1e33b4b6a5bf6a8da1882975f69c77a7 job1/nlte_0000.out -1c4b1ccb2ea3bd56f3ef976e4dce870e job1/nonthermalspec_0000.out -758b51bf02e111b31ec301533cd3bc7b job1/radfield_0000.out \ No newline at end of file diff --git a/tests/nebularonezone_inputfiles/results_md5_job0.txt b/tests/nebularonezone_inputfiles/results_md5_job0.txt deleted file mode 100644 index 5a9f515ce..000000000 --- a/tests/nebularonezone_inputfiles/results_md5_job0.txt +++ /dev/null @@ -1,19 +0,0 @@ -325f0ee7e7b1bbf0b8a5cf401361a987 absorption.out -aff44ecad68d986f04fcd6110331ba8b bflist.out -150cb02fabc4d14108e58eb5b71598d6 deposition.out -8fa4c02a21a902cfab63b9b88fe39f3e emission.out -49b8fe86ed2b3b68fa04624da422c539 emissiontrue.out -c36666a8401b814ea3d785d34cfda8dc gamma_light_curve.out -057b226c371f3819cba5e04bfea3d114 gammalinelist.out -47dd2e31cc98d5d1dda67520fb399429 grid.out -9b992112c19b4378db1c63b0c4a02b1d light_curve.out -9773becefdfe4afffb041b703210c67c linestat.out -98195ccb920b6831d137861c8c6cbfa7 modelgridrankassignments.out -78e9c5effc649781796814311221a203 packets00_0000.out -bb6db91444da92febf54c79bae418810 packets00_0001.out -bcb43f7ee46596bd24e0ab90774d93e4 spec.out -8e7163982f1aa938dc1505478b8c60d1 timesteps.out -08eb1796a7f9729f012a3692abd5c5ee job0/estimators_0000.out -5aa018922ab0ed82383d2b909d44cc6c job0/nlte_0000.out -1c4b1ccb2ea3bd56f3ef976e4dce870e job0/nonthermalspec_0000.out -d013568a0d7519e4613fa07607ab0fb5 job0/radfield_0000.out \ No newline at end of file diff --git a/tests/setup_classicmode.sh b/tests/setup_classicmode.sh deleted file mode 100755 index 5da824a82..000000000 --- a/tests/setup_classicmode.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env zsh - -set -x - -runfolder=classicmode_testrun - -mkdir -p $runfolder - -if [ ! -f atomicdata_classic.tar.xz ]; then curl -O https://theory.gsi.de/~lshingle/artis_http_public/artis/atomicdata_classic.tar.xz; fi - -tar -xf atomicdata_classic.tar.xz --directory $runfolder/ - -rsync -av classicmode_inputfiles/ $runfolder/ - -cp ../data/* $runfolder/ - -cp ../artisoptions_classic.h $runfolder/artisoptions.h - -sed -i'' -e 's/constexpr int MPKTS.*/constexpr int MPKTS = 15000;/g' $runfolder/artisoptions.h - -sed -i'' -e 's/constexpr bool WRITE_PARTIAL_EMISSIONABSORPTIONSPEC.*/constexpr bool WRITE_PARTIAL_EMISSIONABSORPTIONSPEC = true;/g' $runfolder/artisoptions.h - -sed -i'' -e 's/constexpr bool VPKT_ON.*/constexpr bool VPKT_ON = true;/g' $runfolder/artisoptions.h - -set +x diff --git a/tests/setup_classicmode_1d_3dgrid.sh b/tests/setup_classicmode_1d_3dgrid.sh new file mode 100755 index 000000000..2e354f23d --- /dev/null +++ b/tests/setup_classicmode_1d_3dgrid.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env zsh + +set -x + +runfolder=classicmode_1d_3dgrid_testrun + +mkdir -p $runfolder + +if [ ! -f atomicdata_classic.tar.xz ]; then curl -O https://theory.gsi.de/~lshingle/artis_http_public/artis/atomicdata_classic.tar.xz; fi + +tar -xf atomicdata_classic.tar.xz --directory $runfolder/ + +rsync -av classicmode_1d_3dgrid_inputfiles/ $runfolder/ + +cp ../data/* $runfolder/ + +cp ../artisoptions_classic.h $runfolder/artisoptions.h + +cd $runfolder + +sed -i'' -e 's/constexpr int MPKTS.*/constexpr int MPKTS = 15000;/g' artisoptions.h + +sed -i'' -e 's/constexpr int GRID_TYPE.*/constexpr int GRID_TYPE = GRID_CARTESIAN3D;/g' artisoptions.h + +sed -i'' -e 's/constexpr int CUBOID_NCOORDGRID_X.*/constexpr int CUBOID_NCOORDGRID_X = 100;/g' artisoptions.h +sed -i'' -e 's/constexpr int CUBOID_NCOORDGRID_Y.*/constexpr int CUBOID_NCOORDGRID_Y = 100;/g' artisoptions.h +sed -i'' -e 's/constexpr int CUBOID_NCOORDGRID_Z.*/constexpr int CUBOID_NCOORDGRID_Z = 100;/g' artisoptions.h + +sed -i'' -e 's/constexpr bool WRITE_PARTIAL_EMISSIONABSORPTIONSPEC.*/constexpr bool WRITE_PARTIAL_EMISSIONABSORPTIONSPEC = true;/g' artisoptions.h + +sed -i'' -e 's/constexpr bool VPKT_ON.*/constexpr bool VPKT_ON = true;/g' artisoptions.h + +cd - + +set +x diff --git a/tests/setup_classicmode_3d.sh b/tests/setup_classicmode_3d.sh index c64f595b8..a5eccd6fc 100755 --- a/tests/setup_classicmode_3d.sh +++ b/tests/setup_classicmode_3d.sh @@ -2,25 +2,34 @@ set -x -rsync -av classicmode_3d_inputfiles/ classicmode_3d_testrun/ +runfolder=classicmode_3d_testrun -xz -d -T0 -v classicmode_3d_testrun/*.xz +mkdir -p $runfolder if [ ! -f atomicdata_feconi.tar.xz ]; then curl -O https://theory.gsi.de/~lshingle/artis_http_public/artis/atomicdata_feconi.tar.xz; fi -tar -xf atomicdata_feconi.tar.xz --directory classicmode_3d_testrun/ +tar -xf atomicdata_feconi.tar.xz --directory $runfolder/ -cp ../data/* classicmode_3d_testrun/ +rsync -av classicmode_3d_inputfiles/ $runfolder/ -cp ../artisoptions_classic.h classicmode_3d_testrun/artisoptions.h +cp ../data/* $runfolder/ -sed -i'' -e 's/constexpr int MPKTS.*/constexpr int MPKTS = 15000;/g' classicmode_3d_testrun/artisoptions.h +cp ../artisoptions_classic.h $runfolder/artisoptions.h -sed -i'' -e 's/constexpr int CUBOID_NCOORDGRID_X.*/constexpr int CUBOID_NCOORDGRID_X = 10;/g' classicmode_3d_testrun/artisoptions.h -sed -i'' -e 's/constexpr int CUBOID_NCOORDGRID_Y.*/constexpr int CUBOID_NCOORDGRID_Y = 10;/g' classicmode_3d_testrun/artisoptions.h -sed -i'' -e 's/constexpr int CUBOID_NCOORDGRID_Z.*/constexpr int CUBOID_NCOORDGRID_Z = 10;/g' classicmode_3d_testrun/artisoptions.h +cd $runfolder -sed -i'' -e 's/constexpr bool WRITE_PARTIAL_EMISSIONABSORPTIONSPEC.*/constexpr bool WRITE_PARTIAL_EMISSIONABSORPTIONSPEC = true;/g' classicmode_3d_testrun/artisoptions.h +xz -dv -T0 *.xz +sed -i'' -e 's/constexpr int MPKTS.*/constexpr int MPKTS = 15000;/g' artisoptions.h + +sed -i'' -e 's/constexpr int GRID_TYPE.*/constexpr int GRID_TYPE = GRID_CARTESIAN3D;/g' artisoptions.h + +sed -i'' -e 's/constexpr int CUBOID_NCOORDGRID_X.*/constexpr int CUBOID_NCOORDGRID_X = 10;/g' artisoptions.h +sed -i'' -e 's/constexpr int CUBOID_NCOORDGRID_Y.*/constexpr int CUBOID_NCOORDGRID_Y = 10;/g' artisoptions.h +sed -i'' -e 's/constexpr int CUBOID_NCOORDGRID_Z.*/constexpr int CUBOID_NCOORDGRID_Z = 10;/g' artisoptions.h + +sed -i'' -e 's/constexpr bool WRITE_PARTIAL_EMISSIONABSORPTIONSPEC.*/constexpr bool WRITE_PARTIAL_EMISSIONABSORPTIONSPEC = true;/g' artisoptions.h + +cd - set +x diff --git a/tests/setup_kilonova.sh b/tests/setup_kilonova_1d_1dgrid.sh similarity index 57% rename from tests/setup_kilonova.sh rename to tests/setup_kilonova_1d_1dgrid.sh index ef9832d56..c9769965c 100755 --- a/tests/setup_kilonova.sh +++ b/tests/setup_kilonova_1d_1dgrid.sh @@ -2,24 +2,32 @@ set -x -mkdir -p kilonova_testrun +runfolder=kilonova_1d_1dgrid_testrun + +mkdir -p $runfolder if [ ! -f atomicdata_feconi.tar.xz ]; then curl -O https://theory.gsi.de/~lshingle/artis_http_public/artis/atomicdata_feconi.tar.xz; fi -tar -xf atomicdata_feconi.tar.xz --directory kilonova_testrun/ +tar -xf atomicdata_feconi.tar.xz --directory $runfolder/ + +# same input files as the other test run +rsync -av kilonova_1d_3dgrid_inputfiles/ $runfolder/ -rsync -av kilonova_inputfiles/ kilonova_testrun/ +# for the checksum files +rsync -av --ignore-times kilonova_1d_1dgrid_inputfiles/ $runfolder/ -cp ../data/* kilonova_testrun/ +cp ../data/* $runfolder/ -cp ../artisoptions_kilonova_lte.h kilonova_testrun/artisoptions.h +cp ../artisoptions_kilonova_lte.h $runfolder/artisoptions.h -cd kilonova_testrun +cd $runfolder -xz -dvk -T0 *.xz +xz -dv -T0 *.xz sed -i'' -e 's/constexpr int MPKTS.*/constexpr int MPKTS = 80000;/g' artisoptions.h +sed -i'' -e 's/constexpr int GRID_TYPE.*/constexpr int GRID_TYPE = GRID_SPHERICAL1D;/g' artisoptions.h + sed -i'' -e 's/constexpr int TABLESIZE.*/constexpr int TABLESIZE = 20;/g' artisoptions.h sed -i'' -e 's/constexpr double MINTEMP.*/constexpr double MINTEMP = 1000.;/g' artisoptions.h sed -i'' -e 's/constexpr double MAXTEMP.*/constexpr double MAXTEMP = 20000.;/g' artisoptions.h diff --git a/tests/setup_kilonova_1d_3dgrid.sh b/tests/setup_kilonova_1d_3dgrid.sh new file mode 100755 index 000000000..700ceebed --- /dev/null +++ b/tests/setup_kilonova_1d_3dgrid.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env zsh + +set -x + +runfolder=kilonova_1d_3dgrid_testrun + +mkdir -p $runfolder + +if [ ! -f atomicdata_feconi.tar.xz ]; then curl -O https://theory.gsi.de/~lshingle/artis_http_public/artis/atomicdata_feconi.tar.xz; fi + +tar -xf atomicdata_feconi.tar.xz --directory $runfolder/ + +rsync -av kilonova_1d_3dgrid_inputfiles/ $runfolder/ + +cp ../data/* $runfolder/ + +cp ../artisoptions_kilonova_lte.h $runfolder/artisoptions.h + +cd $runfolder + +xz -dv -T0 *.xz + +sed -i'' -e 's/constexpr int MPKTS.*/constexpr int MPKTS = 80000;/g' artisoptions.h + +sed -i'' -e 's/constexpr int GRID_TYPE.*/constexpr int GRID_TYPE = GRID_CARTESIAN3D;/g' artisoptions.h + +sed -i'' -e 's/constexpr int CUBOID_NCOORDGRID_X.*/constexpr int CUBOID_NCOORDGRID_X = 50;/g' artisoptions.h +sed -i'' -e 's/constexpr int CUBOID_NCOORDGRID_Y.*/constexpr int CUBOID_NCOORDGRID_Y = 50;/g' artisoptions.h +sed -i'' -e 's/constexpr int CUBOID_NCOORDGRID_Z.*/constexpr int CUBOID_NCOORDGRID_Z = 50;/g' artisoptions.h + +sed -i'' -e 's/constexpr int TABLESIZE.*/constexpr int TABLESIZE = 20;/g' artisoptions.h +sed -i'' -e 's/constexpr double MINTEMP.*/constexpr double MINTEMP = 1000.;/g' artisoptions.h +sed -i'' -e 's/constexpr double MAXTEMP.*/constexpr double MAXTEMP = 20000.;/g' artisoptions.h + +sed -i'' -e 's/constexpr bool WRITE_PARTIAL_EMISSIONABSORPTIONSPEC.*/constexpr bool WRITE_PARTIAL_EMISSIONABSORPTIONSPEC = true;/g' artisoptions.h + +cd - + +set +x diff --git a/tests/setup_kilonova_2d_2dgrid.sh b/tests/setup_kilonova_2d_2dgrid.sh new file mode 100755 index 000000000..8530eb8ca --- /dev/null +++ b/tests/setup_kilonova_2d_2dgrid.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env zsh + +set -x + +runfolder=kilonova_2d_2dgrid_testrun + +mkdir -p $runfolder + +if [ ! -f atomicdata_feconi.tar.xz ]; then curl -O https://theory.gsi.de/~lshingle/artis_http_public/artis/atomicdata_feconi.tar.xz; fi + +tar -xf atomicdata_feconi.tar.xz --directory $runfolder/ + +# same input files as the other test run +rsync -av kilonova_2d_3dgrid_inputfiles/ $runfolder/ + +# for the checksum files +rsync -av --ignore-times kilonova_2d_2dgrid_inputfiles/ $runfolder/ + +cp ../data/* $runfolder/ + +cp ../artisoptions_kilonova_lte.h $runfolder/artisoptions.h + +cd $runfolder + +xz -dv -T0 *.xz + +sed -i'' -e 's/constexpr int MPKTS.*/constexpr int MPKTS = 80000;/g' artisoptions.h + +sed -i'' -e 's/constexpr int GRID_TYPE.*/constexpr int GRID_TYPE = GRID_CYLINDRICAL2D;/g' artisoptions.h + +sed -i'' -e 's/constexpr int TABLESIZE.*/constexpr int TABLESIZE = 20;/g' artisoptions.h +sed -i'' -e 's/constexpr double MINTEMP.*/constexpr double MINTEMP = 1000.;/g' artisoptions.h +sed -i'' -e 's/constexpr double MAXTEMP.*/constexpr double MAXTEMP = 20000.;/g' artisoptions.h + +cd - + +set +x diff --git a/tests/setup_kilonova_2d_3dgrid.sh b/tests/setup_kilonova_2d_3dgrid.sh new file mode 100755 index 000000000..589cfefcd --- /dev/null +++ b/tests/setup_kilonova_2d_3dgrid.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env zsh + +set -x + +runfolder=kilonova_2d_3dgrid_testrun + +mkdir -p $runfolder + +if [ ! -f atomicdata_feconi.tar.xz ]; then curl -O https://theory.gsi.de/~lshingle/artis_http_public/artis/atomicdata_feconi.tar.xz; fi + +tar -xf atomicdata_feconi.tar.xz --directory $runfolder/ + +rsync -av kilonova_2d_3dgrid_inputfiles/ $runfolder/ + +cp ../data/* $runfolder/ + +cp ../artisoptions_kilonova_lte.h $runfolder/artisoptions.h + +cd $runfolder + +xz -dv -T0 *.xz + +sed -i'' -e 's/constexpr int MPKTS.*/constexpr int MPKTS = 80000;/g' artisoptions.h + +sed -i'' -e 's/constexpr int GRID_TYPE.*/constexpr int GRID_TYPE = GRID_CARTESIAN3D;/g' artisoptions.h + +sed -i'' -e 's/constexpr int CUBOID_NCOORDGRID_X.*/constexpr int CUBOID_NCOORDGRID_X = 50;/g' artisoptions.h +sed -i'' -e 's/constexpr int CUBOID_NCOORDGRID_Y.*/constexpr int CUBOID_NCOORDGRID_Y = 50;/g' artisoptions.h +sed -i'' -e 's/constexpr int CUBOID_NCOORDGRID_Z.*/constexpr int CUBOID_NCOORDGRID_Z = 50;/g' artisoptions.h + +sed -i'' -e 's/constexpr int TABLESIZE.*/constexpr int TABLESIZE = 20;/g' artisoptions.h +sed -i'' -e 's/constexpr double MINTEMP.*/constexpr double MINTEMP = 1000.;/g' artisoptions.h +sed -i'' -e 's/constexpr double MAXTEMP.*/constexpr double MAXTEMP = 20000.;/g' artisoptions.h + +cd - + +set +x diff --git a/tests/setup_nebularonezone.sh b/tests/setup_nebularonezone_1d_3dgrid.sh similarity index 57% rename from tests/setup_nebularonezone.sh rename to tests/setup_nebularonezone_1d_3dgrid.sh index 7b1a00e19..304ca0fea 100755 --- a/tests/setup_nebularonezone.sh +++ b/tests/setup_nebularonezone_1d_3dgrid.sh @@ -2,20 +2,28 @@ set -x -rsync -av nebularonezone_inputfiles/ nebularonezone_testrun/ +runfolder=nebularonezone_1d_3dgrid_testrun + +rsync -av nebularonezone_1d_3dgrid_inputfiles/ nebularonezone_1d_3dgrid_testrun/ if [ ! -f atomicdata_feconi.tar.xz ]; then curl -O https://theory.gsi.de/~lshingle/artis_http_public/artis/atomicdata_feconi.tar.xz; fi -tar -xf atomicdata_feconi.tar.xz --directory nebularonezone_testrun/ +tar -xf atomicdata_feconi.tar.xz --directory nebularonezone_1d_3dgrid_testrun/ -cp ../data/* nebularonezone_testrun/ +cp ../data/* nebularonezone_1d_3dgrid_testrun/ -cp ../artisoptions_nltenebular.h nebularonezone_testrun/artisoptions.h +cp ../artisoptions_nltenebular.h nebularonezone_1d_3dgrid_testrun/artisoptions.h -cd nebularonezone_testrun +cd nebularonezone_1d_3dgrid_testrun sed -i'' -e 's/constexpr int MPKTS.*/constexpr int MPKTS = 1000000;/g' artisoptions.h +sed -i'' -e 's/constexpr int GRID_TYPE.*/constexpr int GRID_TYPE = GRID_CARTESIAN3D;/g' artisoptions.h + +sed -i'' -e 's/constexpr int CUBOID_NCOORDGRID_X.*/constexpr int CUBOID_NCOORDGRID_X = 50;/g' artisoptions.h +sed -i'' -e 's/constexpr int CUBOID_NCOORDGRID_Y.*/constexpr int CUBOID_NCOORDGRID_Y = 50;/g' artisoptions.h +sed -i'' -e 's/constexpr int CUBOID_NCOORDGRID_Z.*/constexpr int CUBOID_NCOORDGRID_Z = 50;/g' artisoptions.h + sed -i'' -e 's/constexpr int TABLESIZE.*/constexpr int TABLESIZE = 20;/g' artisoptions.h sed -i'' -e 's/constexpr double MINTEMP.*/constexpr double MINTEMP = 2000.;/g' artisoptions.h sed -i'' -e 's/constexpr double MAXTEMP.*/constexpr double MAXTEMP = 10000.;/g' artisoptions.h diff --git a/thermalbalance.cc b/thermalbalance.cc index bae9405ad..8b3f775ce 100644 --- a/thermalbalance.cc +++ b/thermalbalance.cc @@ -1,5 +1,6 @@ #include "thermalbalance.h" +#include #include #include @@ -194,14 +195,16 @@ static auto get_heating_ion_coll_deexc(const int modelgridindex, const int eleme // ---------------------------------------------------------- const int ndowntrans = get_ndowntrans(element, ion, level); for (int i = 0; i < ndowntrans; i++) { - const int lower = globals::elements[element].ions[ion].levels[level].downtrans[i].targetlevelindex; + const auto &downtransition = globals::elements[element].ions[ion].levels[level].downtrans[i]; + const int lower = downtransition.targetlevelindex; const double epsilon_trans = epsilon_level - epsilon(element, ion, lower); - const double C = - nnlevel * col_deexcitation_ratecoeff(T_e, nne, epsilon_trans, element, ion, level, i) * epsilon_trans; + const double C = nnlevel * + col_deexcitation_ratecoeff(T_e, nne, epsilon_trans, element, ion, level, downtransition) * + epsilon_trans; C_deexc += C; } } - // const double nnion = ionstagepop(modelgridindex, element, ion); + // const double nnion = get_nnion(modelgridindex, element, ion); // printout("ion_col_deexc_heating: T_e %g nne %g Z=%d ionstage %d nnion %g heating_contrib %g contrib/nnion %g\n", // T_e, nne, get_atomicnumber(element), get_ionstage(element, ion), nnion, C_deexc, C_deexc / nnion); return C_deexc; @@ -348,26 +351,22 @@ static auto T_e_eqn_heating_minus_cooling(const double T_e, void *paras) -> doub /// Set new T_e guess for the current cell and update populations // globals::cell[cellnumber].T_e = T_e; grid::set_Te(modelgridindex, T_e); - double nntot = NAN; - if (NLTE_POPS_ON && NLTE_POPS_ALL_IONS_SIMULTANEOUS) { - nntot = calculate_electron_densities(modelgridindex); - } else { - nntot = calculate_populations(modelgridindex); - } + calculate_ion_balance_nne(modelgridindex); + const auto nne = grid::get_nne(modelgridindex); /// Then calculate heating and cooling rates - const float nne = grid::get_nne(modelgridindex); kpkt::calculate_cooling_rates(modelgridindex, heatingcoolingrates); calculate_heating_rates(modelgridindex, T_e, nne, heatingcoolingrates); - const double nt_frac_heating = nonthermal::get_nt_frac_heating(modelgridindex); - heatingcoolingrates->heating_dep = nonthermal::get_deposition_rate_density(modelgridindex) * nt_frac_heating; - heatingcoolingrates->nt_frac_heating = nt_frac_heating; + heatingcoolingrates->nt_frac_heating = nonthermal::get_nt_frac_heating(modelgridindex); + heatingcoolingrates->heating_dep = + nonthermal::get_deposition_rate_density(modelgridindex) * heatingcoolingrates->nt_frac_heating; /// Adiabatic cooling term - const double p = nntot * KB * T_e; + const double nntot = get_nnion_tot(modelgridindex) + nne; + const double p = nntot * KB * T_e; // pressure in [erg/cm^3] const double volumetmin = grid::get_modelcell_assocvolume_tmin(modelgridindex); - const double dV = 3 * volumetmin / pow(globals::tmin, 3) * pow(t_current, 2); + const double dV = 3 * volumetmin / pow(globals::tmin, 3) * pow(t_current, 2); // really dV/dt const double V = volumetmin * pow(t_current / globals::tmin, 3); // printout("nntot %g, p %g, dV %g, V %g\n",nntot,p,dV,V); heatingcoolingrates->cooling_adiabatic = p * dV / V; @@ -377,7 +376,7 @@ static auto T_e_eqn_heating_minus_cooling(const double T_e, void *paras) -> doub const double total_coolingrate = heatingcoolingrates->cooling_ff + heatingcoolingrates->cooling_fb + heatingcoolingrates->cooling_collisional + heatingcoolingrates->cooling_adiabatic; - return total_heating_rate - total_coolingrate; // - 0.01*(heatingrates_thisthread->bf+coolingrates[tid].fb)/2; + return total_heating_rate - total_coolingrate; } void call_T_e_finder(const int modelgridindex, const int timestep, const double t_current, const double T_min, @@ -450,10 +449,6 @@ void call_T_e_finder(const int modelgridindex, const int timestep, const double MINTEMP, MAXTEMP, modelgridindex, grid::get_TR(modelgridindex), grid::get_W(modelgridindex)); } - if (neutral_flag) { - printout("[info] call_T_e_finder: cell %d contains only neutral ions\n", modelgridindex); - } - if (T_e > 2 * T_e_old) { T_e = 2 * T_e_old; printout("use T_e damping in cell %d\n", modelgridindex); diff --git a/update_grid.cc b/update_grid.cc index db861dd32..12b5ea0fd 100644 --- a/update_grid.cc +++ b/update_grid.cc @@ -1,10 +1,9 @@ #include "update_grid.h" -#include - #include #include "atomic.h" +#include "constants.h" #include "decay.h" #include "grid.h" #include "kpkt.h" @@ -20,24 +19,6 @@ #include "thermalbalance.h" #include "vpkt.h" -void precalculate_partfuncts(int modelgridindex) -/// The partition functions depend only on T_R and W. This means they don't -/// change during any iteration on T_e. Therefore their precalculation was -/// taken out of calculate_populations to save runtime. -{ - /// Precalculate partition functions for each ion in every cell - /// this saves a factor 10 in calculation time of Saha-Boltzman populations - for (int element = 0; element < get_nelements(); element++) { - const int nions = get_nions(element); - for (int ion = 0; ion < nions; ion++) { - // printout("precalc element %d, ion %d, mgi %d\n",element,ion,modelgridindex); - // globals::cell[cellnumber].composition[element].ltepartfunct[ion] = calculate_ltepartfunct(element,ion,T_R); - grid::modelgrid[modelgridindex].composition[element].partfunct[ion] = - calculate_partfunct(element, ion, modelgridindex); - } - } -} - static void write_to_estimators_file(FILE *estimators_file, const int mgi, const int timestep, const int titer, const struct heatingcoolingrates *heatingcoolingrates) { // return; disable for better performance (if estimators files are not needed) @@ -47,8 +28,8 @@ static void write_to_estimators_file(FILE *estimators_file, const int mgi, const printout("writing to estimators file timestep %d cell %d...\n", timestep, mgi); const auto T_e = grid::get_Te(mgi); - const float nne = grid::get_nne(mgi); - const double Y_e = grid::get_electronfrac(mgi); + const auto nne = grid::get_nne(mgi); + const auto Y_e = grid::get_electronfrac(mgi); // fprintf(estimators_file,"%d %g %g %g %g %d // ",n,get_TR(n),grid::get_Te(n),get_W(n),get_TJ(n),grid::modelgrid[n].thick); fprintf(estimators_file,"%d %g %g %g // %g %g ",n,get_TR(n),grid::get_Te(n),get_W(n),get_TJ(n),grey_optical_depth); @@ -57,12 +38,11 @@ static void write_to_estimators_file(FILE *estimators_file, const int mgi, const "tdays %7.2f\n", timestep, mgi, titer, grid::get_TR(mgi), T_e, grid::get_W(mgi), grid::get_TJ(mgi), grid::modelgrid[mgi].grey_depth, grid::modelgrid[mgi].thick, nne, Y_e, - globals::time_step[timestep].mid / DAY); + globals::timesteps[timestep].mid / DAY); // fprintf(estimators_file,"%d %g %g %g %g %g %g %g //",n,get_TR(n),grid::get_Te(n),get_W(n),get_TJ(n),grey_optical_depth,grey_optical_deptha,compton_optical_depth); - if (NLTE_POPS_ON) // && timestep % 2 == 0 - { + if (globals::total_nlte_levels > 0) { nltepop_write_to_file(mgi, timestep); } @@ -81,15 +61,15 @@ static void write_to_estimators_file(FILE *estimators_file, const int mgi, const } double elpop = 0.; for (int ion = 0; ion < nions; ion++) { - elpop += ionstagepop(mgi, element, ion); - fprintf(estimators_file, " %d: %9.3e", get_ionstage(element, ion), ionstagepop(mgi, element, ion)); + elpop += get_nnion(mgi, element, ion); + fprintf(estimators_file, " %d: %9.3e", get_ionstage(element, ion), get_nnion(mgi, element, ion)); } if (nions == 0) { elpop = grid::get_elem_numberdens(mgi, element); } fprintf(estimators_file, " SUM: %9.3e", elpop); - decay::fprint_nuc_abundances(estimators_file, mgi, globals::time_step[timestep].mid, element); + decay::fprint_nuc_abundances(estimators_file, mgi, globals::timesteps[timestep].mid, element); if (nions == 0 || elpop <= 0.) { // dummy element for nuclear abundances only @@ -371,18 +351,6 @@ static void write_to_estimators_file(FILE *estimators_file, const int mgi, const } fprintf(estimators_file, "\n"); - fprintf(estimators_file, "BF_escfrac_vpkt Z=%2d", get_atomicnumber(element)); - for (int ionstage = 1; ionstage < get_ionstage(element, 0); ionstage++) { - fprintf(estimators_file, " "); - } - for (int ion = 0; ion < nions; ion++) { - const double alpha_r_mc = get_ion_stats(mgi, element, ion, stats::ION_RADRECOMB_MACROATOM) + - get_ion_stats(mgi, element, ion, stats::ION_RADRECOMB_KPKT); - const double alpha_r_mc_escaped = get_ion_stats(mgi, element, ion, stats::ION_RADRECOMB_ESCAPED); - fprintf(estimators_file, " %d: %9.3f", get_ionstage(element, ion), alpha_r_mc_escaped / alpha_r_mc); - } - fprintf(estimators_file, "\n"); - fprintf(estimators_file, "BB_escfrac Z=%2d", get_atomicnumber(element)); for (int ionstage = 1; ionstage < get_ionstage(element, 0); ionstage++) { fprintf(estimators_file, " "); @@ -426,17 +394,17 @@ static void write_to_estimators_file(FILE *estimators_file, const int mgi, const // if (timestep % 20 == 0) // { - // fprintf(estimators_file, "kappa_bf(nuedge) Z=%2d", get_atomicnumber(element)); + // fprintf(estimators_file, "chi_bf(nuedge) Z=%2d", get_atomicnumber(element)); // for (int ionstage = 1; ionstage < get_ionstage(element, 0); ionstage++) // fprintf(estimators_file, " "); // for (int ion = 0; ion < nions - 1; ion++) // { // double nu_edge = (epsilon(element, ion + 1, 0) - epsilon(element, ion, 0)) / H; - // double kappa_bf = calculate_kappa_bf_gammacontr(mgi, nu_edge); + // double chi_bf = calculate_chi_bf_gammacontr(mgi, nu_edge, false); // // fprintf(estimators_file, " %d: %9.3e", // get_ionstage(element, ion), - // kappa_bf); + // chi_bf); // } // fprintf(estimators_file, "\n"); // } @@ -658,15 +626,14 @@ static void write_to_estimators_file(FILE *estimators_file, const int mgi, const if (USE_LUT_PHOTOION && globals::nbfcontinua > 0) { fprintf(estimators_file, "corrphotoionrenorm Z=%2d", get_atomicnumber(element)); for (int ion = 0; ion < nions; ion++) { - fprintf( - estimators_file, " %d: %9.3e", get_ionstage(element, ion), - globals::corrphotoionrenorm[mgi * get_nelements() * get_max_nions() + element * get_max_nions() + ion]); + fprintf(estimators_file, " %d: %9.3e", get_ionstage(element, ion), + globals::corrphotoionrenorm[get_ionestimindex(mgi, element, ion)]); } fprintf(estimators_file, "\n"); fprintf(estimators_file, "gammaestimator Z=%2d", get_atomicnumber(element)); for (int ion = 0; ion < nions; ion++) { fprintf(estimators_file, " %d: %9.3e", get_ionstage(element, ion), - globals::gammaestimator[mgi * get_nelements() * get_max_nions() + element * get_max_nions() + ion]); + globals::gammaestimator[get_ionestimindex(mgi, element, ion)]); } fprintf(estimators_file, "\n"); } @@ -707,7 +674,7 @@ void cellhistory_reset(const int modelgridindex, const bool new_timestep) { const int tid = get_thread_num(); // force rpkt opacities to be recalculated next time they are accessed - globals::kappa_rpkt_cont[tid].recalculate_required = true; + globals::chi_rpkt_cont[tid].recalculate_required = true; globals::cellhistory[tid].cellnumber = modelgridindex; @@ -816,111 +783,78 @@ static void solve_Te_nltepops(const int n, const int nts, const int titer, for (int nlte_iter = 0; nlte_iter <= NLTEITER; nlte_iter++) { const time_t sys_time_start_spencerfano = time(nullptr); if (NT_ON && NT_SOLVE_SPENCERFANO) { - nonthermal::solve_spencerfano(n, nts, - nlte_iter); // depends on the ionization balance, and weakly on nne + // SF solution depends on the ionization balance, and weakly on nne + nonthermal::solve_spencerfano(n, nts, nlte_iter); } const int duration_solve_spencerfano = time(nullptr) - sys_time_start_spencerfano; const time_t sys_time_start_partfuncs_or_gamma = time(nullptr); - if (!NLTE_POPS_ON) { - precalculate_partfuncts(n); - } else if (USE_LUT_PHOTOION && (nlte_iter != 0)) { - // recalculate the Gammas using the current population estimates - for (int element = 0; element < get_nelements(); element++) { + for (int element = 0; element < get_nelements(); element++) { + if (!elem_has_nlte_levels(element)) { + calculate_cellpartfuncts(n, element); + } else if (USE_LUT_PHOTOION && (nlte_iter != 0)) { + // recalculate the Gammas using the current population estimates const int nions = get_nions(element); for (int ion = 0; ion < nions - 1; ion++) { - globals::gammaestimator[n * get_nelements() * get_max_nions() + element * get_max_nions() + ion] = - calculate_iongamma_per_gspop(n, element, ion); + globals::gammaestimator[get_ionestimindex(n, element, ion)] = calculate_iongamma_per_gspop(n, element, ion); } } } const int duration_solve_partfuncs_or_gamma = time(nullptr) - sys_time_start_partfuncs_or_gamma; - /// Find T_e as solution for thermal balance const double prev_T_e = grid::get_Te(n); const time_t sys_time_start_Te = time(nullptr); const int nts_for_te = (titer == 0) ? nts - 1 : nts; - call_T_e_finder(n, nts, globals::time_step[nts_for_te].mid, MINTEMP, MAXTEMP, heatingcoolingrates); + /// Find T_e as solution for thermal balance + call_T_e_finder(n, nts, globals::timesteps[nts_for_te].mid, MINTEMP, MAXTEMP, heatingcoolingrates); const int duration_solve_T_e = time(nullptr) - sys_time_start_Te; - if (!NLTE_POPS_ON || !NLTE_POPS_ALL_IONS_SIMULTANEOUS) // do this in LTE or NLTE single ion solver mode - { - /// Store population values to the grid + if (globals::total_nlte_levels == 0) { const time_t sys_time_start_pops = time(nullptr); - calculate_populations(n); + calculate_ion_balance_nne(n); const int duration_solve_pops = time(nullptr) - sys_time_start_pops; - // calculate_cooling_rates(n); - // calculate_heating_rates(n); + printout( "Grid solver cell %d timestep %d: time spent on: Spencer-Fano %ds, partfuncs/gamma " - "%ds, T_e %ds, " - "populations " - "%ds\n", + "%ds, T_e %ds, populations %ds\n", n, nts, duration_solve_spencerfano, duration_solve_partfuncs_or_gamma, duration_solve_T_e, duration_solve_pops); + break; // no iteration is needed without nlte pops } - if (NLTE_POPS_ON) { + if (globals::total_nlte_levels > 0) { const double fracdiff_T_e = fabs((grid::get_Te(n) / prev_T_e) - 1); const time_t sys_time_start_nltepops = time(nullptr); // fractional difference between previous and current iteration's (nne or max(ground state // population change)) - double nlte_test = 0.; - if (NLTE_POPS_ALL_IONS_SIMULTANEOUS) { - for (int element = 0; element < get_nelements(); element++) { - if (get_nions(element) > 0) { - solve_nlte_pops_element(element, n, nts, nlte_iter); - } - } - } else { - for (int element = 0; element < get_nelements(); element++) { - const int nions = get_nions(element); - for (int ion = 0; ion < nions - 1; ion++) { - const double trial = fabs(solve_nlte_pops_ion(element, ion, n, nts) - 1); - - if (trial > nlte_test) { - nlte_test = trial; - } - } + double fracdiff_nne = 0.; + for (int element = 0; element < get_nelements(); element++) { + if (get_nions(element) > 0) { + solve_nlte_pops_element(element, n, nts, nlte_iter); + calculate_cellpartfuncts(n, element); } } const int duration_solve_nltepops = time(nullptr) - sys_time_start_nltepops; - if (NLTE_POPS_ALL_IONS_SIMULTANEOUS) { - const double nne_prev = grid::get_nne(n); - precalculate_partfuncts(n); - calculate_electron_densities(n); // sets nne - const double fracdiff_nne = fabs((grid::get_nne(n) / nne_prev) - 1); - nlte_test = fracdiff_nne; - printout( - "NLTE solver cell %d timestep %d iteration %d: time spent on: Spencer-Fano %ds, T_e " - "%ds, NLTE " - "populations " - "%ds\n", - n, nts, nlte_iter, duration_solve_spencerfano, duration_solve_T_e, duration_solve_nltepops); - printout( - "NLTE (Spencer-Fano/Te/pops) solver cell %d timestep %d iteration %d: prev_iter nne " - "%g, new nne is %g, " - "fracdiff %g, prev T_e %g new T_e %g fracdiff %g\n", - n, nts, nlte_iter, nne_prev, grid::get_nne(n), nlte_test, prev_T_e, grid::get_Te(n), fracdiff_T_e); - // damp changes in nne if oscillating to much - // grid::set_nne(n, (grid::get_nne(n) + nne_prev) / 2.); - } else { - printout( - "Completed iteration for NLTE population solver in cell %d for timestep %d. " - "Fractional error returned: " - "%g\n", - n, nts, nlte_test); - } + const double nne_prev = grid::get_nne(n); + calculate_ion_balance_nne(n); // sets nne + fracdiff_nne = fabs((grid::get_nne(n) / nne_prev) - 1); + printout( + "NLTE solver cell %d timestep %d iteration %d: time spent on: Spencer-Fano %ds, T_e " + "%ds, NLTE populations %ds\n", + n, nts, nlte_iter, duration_solve_spencerfano, duration_solve_T_e, duration_solve_nltepops); + printout( + "NLTE (Spencer-Fano/Te/pops) solver cell %d timestep %d iteration %d: prev_iter nne " + "%g, new nne is %g, fracdiff %g, prev T_e %g new T_e %g fracdiff %g\n", + n, nts, nlte_iter, nne_prev, grid::get_nne(n), fracdiff_nne, prev_T_e, grid::get_Te(n), fracdiff_T_e); - if (nlte_test <= covergence_tolerance && fracdiff_T_e <= covergence_tolerance) { + if (fracdiff_nne <= covergence_tolerance && fracdiff_T_e <= covergence_tolerance) { printout( "NLTE (Spencer-Fano/Te/pops) solver nne converged to tolerance %g <= %g and T_e to " - "tolerance %g <= %g " - "after %d iterations.\n", - nlte_test, covergence_tolerance, fracdiff_T_e, covergence_tolerance, nlte_iter + 1); + "tolerance %g <= %g after %d iterations.\n", + fracdiff_nne, covergence_tolerance, fracdiff_T_e, covergence_tolerance, nlte_iter + 1); break; } if (nlte_iter == NLTEITER) { @@ -929,8 +863,6 @@ static void solve_Te_nltepops(const int n, const int nts, const int titer, "last iteration\n", nlte_iter + 1); } - } else { - break; // no iteration is needed without NLTE_POPS_ON } } } @@ -941,11 +873,8 @@ static void update_gamma_corrphotoionrenorm_bfheating_estimators(const int n, co for (int element = 0; element < get_nelements(); element++) { const int nions = get_nions(element); for (int ion = 0; ion < nions - 1; ion++) { - const int ionestimindex = n * get_nelements() * get_max_nions() + element * get_max_nions() + ion; - // printout("mgi %d, element %d, ion %d, gammaest - // %g\n",n,element,ion,globals::gammaestimator[ionestimindex]); + const int ionestimindex = get_ionestimindex(n, element, ion); globals::gammaestimator[ionestimindex] *= estimator_normfactor / H; -// printout("mgi %d, element %d, ion %d, gammaest %g\n",n,element,ion,globals::gammaestimator[ionestimindex]); #ifdef DO_TITER if (globals::gammaestimator_save[ionestimindex] >= 0) { globals::gammaestimator[ionestimindex] = @@ -975,20 +904,16 @@ static void update_gamma_corrphotoionrenorm_bfheating_estimators(const int n, co } } if constexpr (USE_LUT_PHOTOION || USE_LUT_BFHEATING) { - /// Then reopen the same loops again. for (int element = 0; element < get_nelements(); element++) { const int nions = get_nions(element); for (int ion = 0; ion < nions - 1; ion++) { /// Reuse the gammaestimator array as temporary storage of the Gamma values during /// the remaining part of the update_grid phase. Afterwards it is reset to record /// the next timesteps gamma estimators. - // nlevels = get_nlevels(element,ion); - // nlevels = get_ionisinglevels(element,ion); - const int ionestimindex = n * get_nelements() * get_max_nions() + element * get_max_nions() + ion; + const int ionestimindex = get_ionestimindex(n, element, ion); if constexpr (USE_LUT_PHOTOION) { globals::gammaestimator[ionestimindex] = calculate_iongamma_per_gspop(n, element, ion); - // printout("mgi %d, element %d, ion %d, Gamma %g\n",n,element,ion,Gamma); } if constexpr (USE_LUT_BFHEATING) { @@ -1014,9 +939,6 @@ static void update_gamma_corrphotoionrenorm_bfheating_estimators(const int n, co element, ion, 0, 0, n, globals::bfheatingestimator[ionestimindex], bfheatingcoeff_ana); abort(); } - - // printout("cell %d element %d ion %d bfheatingestimator - // %g\n",n,element,ion,bfheatingestimator[ionestimindex]); } } } @@ -1041,8 +963,7 @@ static void zero_gammaestimator(const int modelgridindex) { for (int element = 0; element < get_nelements(); element++) { const int nions = get_nions(element); for (int ion = 0; ion < nions; ion++) { - globals::gammaestimator[modelgridindex * get_nelements() * get_max_nions() + element * get_max_nions() + ion] = - 0.; + globals::gammaestimator[get_ionestimindex(modelgridindex, element, ion)] = 0.; } } } @@ -1052,8 +973,7 @@ static void set_all_corrphotoionrenorm(const int modelgridindex, const double va for (int element = 0; element < get_nelements(); element++) { const int nions = get_nions(element); for (int ion = 0; ion < nions; ion++) { - globals::corrphotoionrenorm[modelgridindex * get_nelements() * get_max_nions() + element * get_max_nions() + - ion] = value; + globals::corrphotoionrenorm[get_ionestimindex(modelgridindex, element, ion)] = value; } } } @@ -1065,224 +985,192 @@ static void update_grid_cell(const int mgi, const int nts, const int nts_prev, c const int assoc_cells = grid::get_numassociatedcells(mgi); if (assoc_cells > 0) { const double deltaV = - grid::get_modelcell_assocvolume_tmin(mgi) * pow(globals::time_step[nts_prev].mid / globals::tmin, 3); + grid::get_modelcell_assocvolume_tmin(mgi) * pow(globals::timesteps[nts_prev].mid / globals::tmin, 3); const time_t sys_time_start_update_cell = time(nullptr); - /// Update current mass density of cell - // n = nonemptycells[my_rank+ncl*nprocs]; printout("update_grid_cell: working on cell %d before timestep %d titeration %d...\n", mgi, nts, titer); - // n = nonemptycells[ncl]; - // printout("[debug] update_grid: ncl %d is %d non-empty cell updating grid cell %d ... T_e - // %g, rho %g\n",ncl,my_rank+ncl*nprocs,n,globals::cell[n].T_e,globals::cell[n].rho); - grid::modelgrid[mgi].rho = grid::get_rho_tmin(mgi) / pow(tratmid, 3); - // globals::cell[n].rho = globals::cell[n].rho_init / pow(tratmid,3); - // rho = globals::cell[n].rho; - /// This is done outside update grid now - // grid::modelgrid[n].totalcooling = COOLING_UNDEFINED; - - /// Update abundances of radioactive isotopes - decay::update_abundances(mgi, nts, globals::time_step[nts].mid); - const double estimator_normfactor = 1 / deltaV / deltat / globals::nprocs; - const double estimator_normfactor_over4pi = ONEOVER4PI * estimator_normfactor; - if (globals::opacity_case >= 4) { - if (nts == globals::itstep && titer == 0) { - // For the initial timestep, temperatures have already been assigned - // either by trapped energy release calculation, or reading from gridsave file + /// Update current mass density of cell + grid::set_rho(mgi, grid::get_rho_tmin(mgi) / pow(tratmid, 3)); - if constexpr (USE_LUT_PHOTOION) { - /// Determine renormalisation factor for corrected photoionization cross-sections - if (!globals::simulation_continued_from_saved) { - set_all_corrphotoionrenorm(mgi, 1.); - } - } + /// Update elemental abundances with radioactive decays + decay::update_abundances(mgi, nts, globals::timesteps[nts].mid); - /// W == 1 indicates that this modelgrid cell was treated grey in the - /// last timestep. Therefore it has no valid Gamma estimators and must - /// be treated in LTE at restart. - if (grid::modelgrid[mgi].thick == 0 && grid::get_W(mgi) == 1) { - printout( - "force modelgrid cell %d to grey/LTE for update grid since existing W == 1. (will not have gamma " - "estimators)\n", - mgi); - grid::modelgrid[mgi].thick = 1; - } - printout("initial_iteration %d\n", globals::initial_iteration); - printout("mgi %d modelgrid.thick: %d (for this grid update only)\n", mgi, grid::modelgrid[mgi].thick); + const double estimator_normfactor = 1 / deltaV / deltat / globals::nprocs; + const double estimator_normfactor_over4pi = ONEOVER4PI * estimator_normfactor; - precalculate_partfuncts(mgi); + if (globals::opacity_case < 4) { + // various forms of grey opacity + grid::modelgrid[mgi].thick = 1; - if (!globals::simulation_continued_from_saved || !NLTE_POPS_ON || globals::initial_iteration || - grid::modelgrid[mgi].thick == 1) { - calculate_populations(mgi); // these were not read from the gridsave file, so calculate them now + if (globals::opacity_case == 3) { + // printout("update_grid: opacity_case 3 ... updating globals::cell[n].chi_grey"); //MK + if (grid::get_rho(mgi) > globals::rho_crit) { + grid::set_kappagrey(mgi, globals::opcase3_normal * (0.9 * grid::get_ffegrp(mgi) + 0.1) * globals::rho_crit / + grid::get_rho(mgi)); } else { - calculate_electron_densities(mgi); + grid::set_kappagrey(mgi, globals::opcase3_normal * (0.9 * grid::get_ffegrp(mgi) + 0.1)); } - } else { - /// For all other timesteps temperature corrections have to be applied - - /// we have to calculate the electron density - /// and all the level populations - /// Normalise estimators and make sure that they are finite. - /// Then update T_R and W using the estimators. - /// (This could in principle also be done for empty cells) - - const time_t sys_time_start_temperature_corrections = time(nullptr); - - radfield::normalise_J(mgi, estimator_normfactor_over4pi); // this applies normalisation to the fullspec J - radfield::set_J_normfactor(mgi, - estimator_normfactor_over4pi); // this stores the factor that will be applied - // later for the J bins but not fullspec J + } + } -#ifdef DO_TITER - radfield::titer_J(mgi); -#endif + if (nts == globals::timestep_initial && titer == 0) { + // For the initial timestep, temperatures have already been assigned + // either by trapped energy release calculation, or reading from gridsave file - if constexpr (TRACK_ION_STATS) { - stats::normalise_ion_estimators(mgi, deltat, deltaV); - } + if (USE_LUT_PHOTOION && !globals::simulation_continued_from_saved) { + /// Determine renormalisation factor for corrected photoionization cross-sections + set_all_corrphotoionrenorm(mgi, 1.); + } - // initial_iteration really means either ts 0 or nts < globals::num_lte_timesteps - if (globals::initial_iteration || grid::modelgrid[mgi].thick == 1) { - // LTE mode or grey mode (where temperature doesn't matter but is calculated anyway) + /// W == 1 indicates that this modelgrid cell was treated grey in the + /// last timestep. Therefore it has no valid Gamma estimators and must + /// be treated in LTE at restart. + if (grid::modelgrid[mgi].thick == 0 && grid::get_W(mgi) == 1) { + printout( + "force modelgrid cell %d to grey/LTE for update grid since existing W == 1. (will not have gamma " + "estimators)\n", + mgi); + grid::modelgrid[mgi].thick = 1; + } - const double T_J = radfield::get_T_J_from_J(mgi); - grid::set_TR(mgi, T_J); - grid::set_Te(mgi, T_J); - grid::set_TJ(mgi, T_J); - grid::set_W(mgi, 1); + printout("lte_iteration %d\n", globals::lte_iteration); + printout("mgi %d modelgrid.thick: %d (for this grid update only)\n", mgi, grid::modelgrid[mgi].thick); - if constexpr (USE_LUT_PHOTOION) { - set_all_corrphotoionrenorm(mgi, 1.); - } + for (int element = 0; element < get_nelements(); element++) { + calculate_cellpartfuncts(mgi, element); + } + if (!globals::simulation_continued_from_saved) { + calculate_ion_balance_nne(mgi); + } + } else { + // For all other timesteps temperature corrections have to be applied - precalculate_partfuncts(mgi); - calculate_populations(mgi); - } else // not (initial_iteration || grid::modelgrid[n].thick == 1) - { - // non-LTE timesteps with T_e from heating/cooling + /// we have to calculate the electron density + /// and all the level populations + /// Normalise estimators and make sure that they are finite. + /// Then update T_R and W using the estimators. + /// (This could in principle also be done for empty cells) - radfield::normalise_nuJ(mgi, estimator_normfactor_over4pi); + const time_t sys_time_start_temperature_corrections = time(nullptr); - globals::ffheatingestimator[mgi] *= estimator_normfactor; - globals::colheatingestimator[mgi] *= estimator_normfactor; + radfield::normalise_J(mgi, estimator_normfactor_over4pi); // this applies normalisation to the fullspec J + radfield::set_J_normfactor(mgi, + estimator_normfactor_over4pi); // this stores the factor that will be applied + // later for the J bins but not fullspec J #ifdef DO_TITER - radfield::titer_nuJ(mgi); - titer_average_estimators(mgi); + radfield::titer_J(mgi); #endif - if constexpr (USE_LUT_PHOTOION || USE_LUT_BFHEATING) { - update_gamma_corrphotoionrenorm_bfheating_estimators(mgi, estimator_normfactor); - } + if constexpr (TRACK_ION_STATS) { + stats::normalise_ion_estimators(mgi, deltat, deltaV); + } - // Get radiation field parameters (T_J, T_R, W, and bins if enabled) out of the - // full-spectrum and binned J and nuJ estimators - radfield::fit_parameters(mgi, nts); + // lte_iteration really means either ts 0 or nts < globals::num_lte_timesteps + if (globals::lte_iteration || grid::modelgrid[mgi].thick == 1) { + // LTE mode or grey mode (where temperature doesn't matter but is calculated anyway) - if constexpr (DETAILED_BF_ESTIMATORS_ON) { - radfield::normalise_bf_estimators(mgi, estimator_normfactor / H); - } + const double T_J = radfield::get_T_J_from_J(mgi); + grid::set_TR(mgi, T_J); + grid::set_Te(mgi, T_J); + grid::set_TJ(mgi, T_J); + grid::set_W(mgi, 1); - solve_Te_nltepops(mgi, nts, titer, heatingcoolingrates); + if constexpr (USE_LUT_PHOTOION) { + set_all_corrphotoionrenorm(mgi, 1.); } - printout("Temperature/NLTE solution for cell %d timestep %d took %ld seconds\n", mgi, nts, - time(nullptr) - sys_time_start_temperature_corrections); - } - const float nne = grid::get_nne(mgi); - const double compton_optical_depth = SIGMA_T * nne * grid::wid_init(mgi) * tratmid; - - double radial_pos = grid::modelgrid[mgi].initial_radial_pos_sum * tratmid / assoc_cells; - if (GRID_TYPE == GRID_SPHERICAL1D) { - const double r_inner = grid::get_cellcoordmin(mgi, 0) * tratmid; - const double r_outer = r_inner + grid::wid_init(mgi) * tratmid; - radial_pos = 3. / 4 * (pow(r_outer, 4.) - pow(r_inner, 4.)) / - (pow(r_outer, 3) - pow(r_inner, 3.)); // volume averaged mean radius - // printout("r_inner %g r_outer %g tratmid %g assoc_cells %d\n", r_inner, r_outer, - // tratmid, assoc_cells); - } - const double grey_optical_deptha = grid::get_kappagrey(mgi) * grid::get_rho(mgi) * grid::wid_init(mgi) * tratmid; - // cube corners will have radial pos > rmax, so clamp to 0. - const double dist_to_obs = std::max(0., globals::rmax * tratmid - radial_pos); - const double grey_optical_depth = grid::get_kappagrey(mgi) * grid::get_rho(mgi) * dist_to_obs; - printout( - "modelgridcell %d, compton optical depth (/propgridcell) %g, grey optical depth " - "(/propgridcell) %g\n", - mgi, compton_optical_depth, grey_optical_deptha); - printout("radial_pos %g, distance_to_obs %g, tau_dist %g\n", radial_pos, dist_to_obs, grey_optical_depth); + for (int element = 0; element < get_nelements(); element++) { + calculate_cellpartfuncts(mgi, element); + } + calculate_ion_balance_nne(mgi); + } else { + // not lte_iteration and not a thick cell + // non-LTE timesteps with T_e from heating/cooling - grid::modelgrid[mgi].grey_depth = grey_optical_depth; + radfield::normalise_nuJ(mgi, estimator_normfactor_over4pi); - // grey_optical_depth = compton_optical_depth; + globals::ffheatingestimator[mgi] *= estimator_normfactor; + globals::colheatingestimator[mgi] *= estimator_normfactor; - if ((grey_optical_depth >= globals::cell_is_optically_thick) && (nts < globals::num_grey_timesteps)) { - printout("timestep %d cell %d is treated in grey approximation (kappa_grey %g [cm2/g], tau %g >= %g)\n", nts, - mgi, grid::get_kappagrey(mgi), grey_optical_depth, globals::cell_is_optically_thick); - grid::modelgrid[mgi].thick = 1; - } else if (VPKT_ON && (grey_optical_depth > cell_is_optically_thick_vpkt)) { - grid::modelgrid[mgi].thick = 2; - } else { - grid::modelgrid[mgi].thick = 0; - } +#ifdef DO_TITER + radfield::titer_nuJ(mgi); + titer_average_estimators(mgi); +#endif - if (grid::modelgrid[mgi].thick == 1) { - // cooling rates calculation can be skipped for thick cells - // flag with negative numbers to indicate that the rates are invalid - grid::modelgrid[mgi].totalcooling = -1.; - const int element = 0; - const int ion = 0; - grid::modelgrid[mgi].cooling_contrib_ion[element][ion] = -1.; - } else if (globals::simulation_continued_from_saved && nts == globals::itstep) { - // cooling rates were read from the gridsave file for this timestep - // make sure they are valid - assert_always(grid::modelgrid[mgi].totalcooling >= 0.); - const int element = 0; - const int ion = 0; - assert_always(grid::modelgrid[mgi].cooling_contrib_ion[element][ion] >= 0.); - } else { - /// Cooling rates depend only on cell properties, precalculate total cooling - /// and ion contributions inside update grid and communicate between MPI tasks - const time_t sys_time_start_calc_kpkt_rates = time(nullptr); + if constexpr (USE_LUT_PHOTOION || USE_LUT_BFHEATING) { + update_gamma_corrphotoionrenorm_bfheating_estimators(mgi, estimator_normfactor); + } - printout("calculate_cooling_rates for timestep %d cell %d...", nts, mgi); + // Get radiation field parameters (T_J, T_R, W, and bins if enabled) out of the + // full-spectrum and binned J and nuJ estimators + radfield::fit_parameters(mgi, nts); - // don't pass pointer to heatingcoolingrates because current populations and rates weren't - // used to determine T_e - kpkt::calculate_cooling_rates(mgi, nullptr); + if constexpr (DETAILED_BF_ESTIMATORS_ON) { + radfield::normalise_bf_estimators(mgi, estimator_normfactor / H); + } - printout("took %ld seconds\n", time(nullptr) - sys_time_start_calc_kpkt_rates); + solve_Te_nltepops(mgi, nts, titer, heatingcoolingrates); } - } else { - // For opacity_case != 4 the opacity treatment is grey. Enforce - // optically thick treatment in this case (should be equivalent to grey) + printout("Temperature/NLTE solution for cell %d timestep %d took %ld seconds\n", mgi, nts, + time(nullptr) - sys_time_start_temperature_corrections); + } + + const float nne = grid::get_nne(mgi); + const double compton_optical_depth = SIGMA_T * nne * grid::wid_init(mgi, 0) * tratmid; + + double const radial_pos = grid::modelgrid[mgi].initial_radial_pos_sum * tratmid / assoc_cells; + const double grey_optical_deptha = grid::get_kappagrey(mgi) * grid::get_rho(mgi) * grid::wid_init(mgi, 0) * tratmid; + // cube corners will have radial pos > rmax, so clamp to 0. + const double dist_to_obs = std::max(0., globals::rmax * tratmid - radial_pos); + const double grey_optical_depth = grid::get_kappagrey(mgi) * grid::get_rho(mgi) * dist_to_obs; + printout( + "modelgridcell %d, compton optical depth (/propgridcell) %g, grey optical depth " + "(/propgridcell) %g\n", + mgi, compton_optical_depth, grey_optical_deptha); + printout("radial_pos %g, distance_to_obs %g, tau_dist %g\n", radial_pos, dist_to_obs, grey_optical_depth); + + grid::modelgrid[mgi].grey_depth = grey_optical_depth; + + // grey_optical_depth = compton_optical_depth; + + if ((grey_optical_depth >= globals::cell_is_optically_thick) && (nts < globals::num_grey_timesteps)) { + printout("timestep %d cell %d is treated in grey approximation (chi_grey %g [cm2/g], tau %g >= %g)\n", nts, mgi, + grid::get_kappagrey(mgi), grey_optical_depth, globals::cell_is_optically_thick); grid::modelgrid[mgi].thick = 1; + } else if (VPKT_ON && (grey_optical_depth > cell_is_optically_thick_vpkt)) { + grid::modelgrid[mgi].thick = 2; + } else { + grid::modelgrid[mgi].thick = 0; + } - /// Need the total number density of bound and free electrons for Compton scattering - calculate_electron_densities(mgi); // if this causes problems, disable the nne calculation (only need nne_tot) + if (grid::modelgrid[mgi].thick == 1) { + // cooling rates calculation can be skipped for thick cells + // flag with negative numbers to indicate that the rates are invalid + grid::modelgrid[mgi].totalcooling = -1.; + const int element = 0; + const int ion = 0; + grid::modelgrid[mgi].cooling_contrib_ion[element][ion] = -1.; + } else if (globals::simulation_continued_from_saved && nts == globals::timestep_initial) { + // cooling rates were read from the gridsave file for this timestep + // make sure they are valid + assert_always(grid::modelgrid[mgi].totalcooling >= 0.); + const int element = 0; + const int ion = 0; + assert_always(grid::modelgrid[mgi].cooling_contrib_ion[element][ion] >= 0.); + } else { + /// Cooling rates depend only on cell properties, precalculate total cooling + /// and ion contributions inside update grid and communicate between MPI tasks + const time_t sys_time_start_calc_kpkt_rates = time(nullptr); - if ((nts - globals::itstep) != 0 || titer != 0) { - radfield::normalise_J(mgi, estimator_normfactor_over4pi); // this applies normalisation to the fullspec J - radfield::set_J_normfactor(mgi, - estimator_normfactor_over4pi); // this stores the factor that will be applied - // later for the J bins but not fullspec J + printout("calculate_cooling_rates for timestep %d cell %d...", nts, mgi); - const double T_J = radfield::get_T_J_from_J(mgi); - grid::set_TR(mgi, T_J); - grid::set_Te(mgi, T_J); - grid::set_TJ(mgi, T_J); - grid::set_W(mgi, 1); - } + // don't pass pointer to heatingcoolingrates because current populations and rates weren't + // used to determine T_e + kpkt::calculate_cooling_rates(mgi, nullptr); - if (globals::opacity_case == 3) { - // printout("update_grid: opacity_case 3 ... updating globals::cell[n].kappa_grey"); //MK - if (grid::get_rho(mgi) > globals::rho_crit) { - grid::set_kappagrey(mgi, globals::opcase3_normal * (0.9 * grid::get_ffegrp(mgi) + 0.1) * globals::rho_crit / - grid::get_rho(mgi)); - } else { - grid::set_kappagrey(mgi, globals::opcase3_normal * (0.9 * grid::get_ffegrp(mgi) + 0.1)); - } - } + printout("took %ld seconds\n", time(nullptr) - sys_time_start_calc_kpkt_rates); } const int update_grid_cell_seconds = time(nullptr) - sys_time_start_update_cell; @@ -1313,12 +1201,12 @@ void update_grid(FILE *estimators_file, const int nts, const int nts_prev, const const time_t sys_time_start_update_grid = time(nullptr); printout("\n"); printout("timestep %d: time before update grid %ld (tstart + %ld) simtime ts_mid %g days\n", nts, - sys_time_start_update_grid, sys_time_start_update_grid - real_time_start, globals::time_step[nts].mid / DAY); + sys_time_start_update_grid, sys_time_start_update_grid - real_time_start, globals::timesteps[nts].mid / DAY); if constexpr (USE_LUT_PHOTOION) { /// Initialise globals::corrphotoionrenorm[i] to zero before update_grid is called /// unless they have been read from file - if ((!globals::simulation_continued_from_saved) || (nts - globals::itstep != 0) || (titer != 0)) { + if ((!globals::simulation_continued_from_saved) || (nts - globals::timestep_initial != 0) || (titer != 0)) { printout("nts %d, titer %d: reset corr photoionrenorm\n", nts, titer); for (int i = 0; i < grid::get_npts_model() * get_nelements() * get_max_nions(); i++) { globals::corrphotoionrenorm[i] = 0.; @@ -1328,7 +1216,7 @@ void update_grid(FILE *estimators_file, const int nts, const int nts_prev, const } // printout("[debug] update_grid: starting update for timestep %d...\n",m); - const double tratmid = globals::time_step[nts].mid / globals::tmin; + const double tratmid = globals::timesteps[nts].mid / globals::tmin; /// Thread private substitution of max_path_step. Its minimum is /// assigned to max_path_step after the parallel update_grid finished. @@ -1342,14 +1230,14 @@ void update_grid(FILE *estimators_file, const int nts, const int nts_prev, const /// regime proportional to the density to a regime independent of the density /// This is done by solving for tau_sobolev == 1 /// tau_sobolev = PI*QE*QE/(ME*C) * rho_crit_para * rho/nucmass(28, 56) * 3000e-8 * - /// globals::time_step[m].mid; + /// globals::timesteps[m].mid; globals::rho_crit = ME * CLIGHT * decay::nucmass(28, 56) / - (PI * QE * QE * globals::rho_crit_para * 3000e-8 * globals::time_step[nts].mid); + (PI * QE * QE * globals::rho_crit_para * 3000e-8 * globals::timesteps[nts].mid); printout("update_grid: rho_crit = %g\n", globals::rho_crit); // These values will not be used if nts == 0, but set them anyway // nts_prev is the previous timestep, unless this is timestep zero - const double deltat = globals::time_step[nts_prev].width; + const double deltat = globals::timesteps[nts_prev].width; // printout("timestep %d, titer %d\n", nts, titer); // printout("deltat %g\n", deltat); @@ -1431,271 +1319,3 @@ void update_grid(FILE *estimators_file, const int nts, const int nts_prev, const nts, time(nullptr), my_rank, time_update_grid_end_thisrank - sys_time_start_update_grid, time(nullptr) - time_update_grid_end_thisrank, time(nullptr) - sys_time_start_update_grid); } - -auto calculate_populations(const int modelgridindex) -> double -/// Determines the electron number density for a given cell using one of -/// libgsl's root_solvers and calculates the depending level populations. -{ - /// and the solution function - struct nne_solution_paras paras { - .cellnumber = modelgridindex - }; - gsl_function f{.function = &nne_solution_f, .params = ¶s}; - - neutral_flag = false; - - /// Get temperatures - const double T_R = grid::get_TR(modelgridindex); - const auto T_e = grid::get_Te(modelgridindex); - const double W = grid::get_W(modelgridindex); - - double nne_hi = grid::get_rho(modelgridindex) / MH; - - /// The following section of uppermost_ion is (so far) NOT thread safe!!!!!!!!!!!!!!!!!!!!!!! - int only_neutral_ions = 0; - int nelements_in_cell = 0; - for (int element = 0; element < get_nelements(); element++) { - const int nions = get_nions(element); - // elements[element].uppermost_ion = nions-1; - grid::set_elements_uppermost_ion(modelgridindex, element, nions - 1); - const double abundance = grid::get_elem_abundance(modelgridindex, element); - if (abundance > 0) { - int uppermost_ion = 0; - if (globals::initial_iteration || grid::modelgrid[modelgridindex].thick == 1) { - uppermost_ion = get_nions(element) - 1; - } else { - int ion = 0; - for (ion = 0; ion < nions - 1; ion++) { - double Gamma = 0.; - if constexpr (!USE_LUT_PHOTOION) { - Gamma = calculate_iongamma_per_gspop(modelgridindex, element, ion); - } else { - Gamma = globals::gammaestimator[modelgridindex * get_nelements() * get_max_nions() + - element * get_max_nions() + ion]; - } - - if ((Gamma == 0) && - (!NT_ON || ((globals::rpkt_emiss[modelgridindex] == 0.) && - (grid::get_modelinitradioabund(modelgridindex, decay::get_nucindex(24, 48)) == 0.) && - (grid::get_modelinitradioabund(modelgridindex, decay::get_nucindex(28, 56)) == 0.)))) { - break; - } - } - uppermost_ion = ion; - } - - double factor = 1.; - int ion = 0; - for (ion = 0; ion < uppermost_ion; ion++) { - factor *= nne_hi * phi(element, ion, modelgridindex); - // printout("element %d, ion %d, factor %g\n",element,i,factor); - if (!std::isfinite(factor)) { - printout( - "[info] calculate_populations: uppermost_ion limited by phi factors for element " - "Z=%d, ionstage %d in " - "cell %d\n", - get_atomicnumber(element), get_ionstage(element, ion), modelgridindex); - break; - } - } - uppermost_ion = ion; - // printout("cell %d, element %d, final uppermost_ion is %d, factor - // %g\n",modelgridindex,element,uppermost_ion,factor); elements[element].uppermost_ion = - // uppermost_ion; - grid::set_elements_uppermost_ion(modelgridindex, element, uppermost_ion); - if (uppermost_ion == 0) { - only_neutral_ions++; - } - nelements_in_cell++; - } - } - - float nne = 0.; - double nne_tot = 0.; /// total number of electrons in grid cell which are possible - /// targets for compton scattering of gamma rays - double nntot = 0.; - if (only_neutral_ions == nelements_in_cell) { - /// Special case of only neutral ions, set nne to some finite value that - /// packets are not lost in kpkts - /// Introduce a flag variable which is sent to the T_e solver so that - /// we get this info only once when T_e is converged and not for each - /// iteration step. - neutral_flag = true; - // printout("[warning] calculate_populations: only neutral ions in cell %d - // modelgridindex\n",modelgridindex); abort(); - /// Now calculate the ground level populations in nebular approximation and store them to the - /// grid - for (int element = 0; element < get_nelements(); element++) { - /// calculate number density of the current element (abundances are given by mass) - const double nnelement = grid::get_elem_numberdens(modelgridindex, element); - nne_tot += nnelement * get_atomicnumber(element); - - const int nions = get_nions(element); - /// Assign the species population to the neutral ion and set higher ions to MINPOP - for (int ion = 0; ion < nions; ion++) { - double nnion = NAN; - if (ion == 0) { - nnion = nnelement; - } else if (nnelement > 0.) { - nnion = MINPOP; - } else { - nnion = 0.; - } - nntot += nnion; - nne += nnion * (get_ionstage(element, ion) - 1); - grid::modelgrid[modelgridindex].composition[element].groundlevelpop[ion] = - (nnion * stat_weight(element, ion, 0) / - grid::modelgrid[modelgridindex].composition[element].partfunct[ion]); - - if (!std::isfinite(grid::modelgrid[modelgridindex].composition[element].groundlevelpop[ion])) { - printout( - "[warning] calculate_populations: groundlevelpop infinite in connection with " - "MINPOP\n"); - } - } - } - nntot += nne; - if (nne < MINPOP) { - nne = MINPOP; - } - grid::set_nne(modelgridindex, nne); - } else { - /// Apply solver to get nne - /// Search solution for nne in [nne_lo,nne_hi] - // printout("nne@x_lo %g\n", nne_solution_f(nne_lo,f.params)); - // printout("nne@x_hi %g\n", nne_solution_f(nne_hi,f.params)); - // printout("n, x_lo, x_hi, T_R, T_e, W, rho %d, %g, %g, %g, %g, %g, - // %g\n",modelgridindex,x_lo,x_hi,T_R,T_e,W,globals::cell[modelgridindex].rho); - double nne_lo = 0.; // MINPOP; - if (nne_solution_f(nne_lo, f.params) * nne_solution_f(nne_hi, f.params) > 0) { - printout("n, nne_lo, nne_hi, T_R, T_e, W, rho %d, %g, %g, %g, %g, %g, %g\n", modelgridindex, nne_lo, nne_hi, T_R, - T_e, W, grid::get_rho(modelgridindex)); - printout("nne@x_lo %g\n", nne_solution_f(nne_lo, f.params)); - printout("nne@x_hi %g\n", nne_solution_f(nne_hi, f.params)); - - for (int element = 0; element < get_nelements(); element++) { - printout("cell %d, element %d, uppermost_ion is %d\n", modelgridindex, element, - grid::get_elements_uppermost_ion(modelgridindex, element)); - - if constexpr (USE_LUT_PHOTOION) { - for (int ion = 0; ion <= grid::get_elements_uppermost_ion(modelgridindex, element); ion++) { - printout("element %d, ion %d, gammaionest %g\n", element, ion, - globals::gammaestimator[modelgridindex * get_nelements() * get_max_nions() + - element * get_max_nions() + ion]); - } - } - } - } - gsl_root_fsolver *solver = gsl_root_fsolver_alloc(gsl_root_fsolver_brent); - - gsl_root_fsolver_set(solver, &f, nne_lo, nne_hi); - constexpr int maxit = 100; - constexpr double fractional_accuracy = 1e-3; - int status = GSL_CONTINUE; - for (int iter = 0; iter <= maxit; iter++) { - iter++; - gsl_root_fsolver_iterate(solver); - nne = gsl_root_fsolver_root(solver); - nne_lo = gsl_root_fsolver_x_lower(solver); - nne_hi = gsl_root_fsolver_x_upper(solver); - status = gsl_root_test_interval(nne_lo, nne_hi, 0, fractional_accuracy); - if (status != GSL_CONTINUE) { - break; - } - } - - gsl_root_fsolver_free(solver); - - if (nne < MINPOP) { - nne = MINPOP; - } - - grid::set_nne(modelgridindex, nne); - if (status == GSL_CONTINUE) { - printout("[warning] calculate_populations: nne did not converge within %d iterations\n", maxit); - } - // printout("[debug] update_grid: status = %s\n",gsl_strerror(status)); - // printout("[debug] update_grid: converged nne %g\n",globals::cell[modelgridindex].nne); - - /// Now calculate the ground level populations in nebular approximation and store them to the - /// grid - // double nne_check = 0.; - nne_tot = 0.; /// total number of electrons in grid cell which are possible - /// targets for compton scattering of gamma rays - - nntot = nne; - for (int element = 0; element < get_nelements(); element++) { - const int nions = get_nions(element); - /// calculate number density of the current element (abundances are given by mass) - const double nnelement = grid::get_elem_numberdens(modelgridindex, element); - nne_tot += nnelement * get_atomicnumber(element); - - const int uppermost_ion = grid::get_elements_uppermost_ion(modelgridindex, element); - auto ionfractions = std::make_unique(uppermost_ion + 1); - - if (nnelement > 0) { - get_ionfractions(element, modelgridindex, nne, ionfractions.get(), uppermost_ion); - } - - /// Use ionizationfractions to calculate the groundlevel populations - for (int ion = 0; ion < nions; ion++) { - double nnion = NAN; - if (ion <= uppermost_ion) { - if (nnelement > 0) { - nnion = nnelement * ionfractions[ion]; - if (nnion < MINPOP) { - nnion = MINPOP; - } - } else { - nnion = 0.; - } - } else { - nnion = MINPOP; /// uppermost_ion is only < nions-1 in cells with nonzero abundance of - /// the given species - } - nntot += nnion; - - grid::modelgrid[modelgridindex].composition[element].groundlevelpop[ion] = - (nnion * stat_weight(element, ion, 0) / - grid::modelgrid[modelgridindex].composition[element].partfunct[ion]); - - if (!std::isfinite(grid::modelgrid[modelgridindex].composition[element].groundlevelpop[ion])) { - printout( - "[warning] calculate_populations: groundlevelpop infinite in connection with " - "MINPOP\n"); - } - } - } - } - - grid::set_nnetot(modelgridindex, nne_tot); - return nntot; -} - -auto calculate_electron_densities(const int modelgridindex) -> double -// Determines the free and total electron number densities -// for a given cell and stores them, assuming ion populations (ground_level_pop and partfunc) -// are fixed (determined by NLTE all-ion solver) -{ - double nne_tot = 0.; // total electron density - float nne = 0.; // free electron density - - for (int element = 0; element < get_nelements(); element++) { - // calculate number density of the current element (abundances are given by mass) - const double nnelement = grid::get_elem_numberdens(modelgridindex, element); - nne_tot += nnelement * get_atomicnumber(element); - - // Use ionization fractions to calculate the free electron contributions - if (nnelement > 0) { - const int nions = get_nions(element); - for (int ion = 0; ion < nions; ion++) { - // if (ion <= globals::elements[element].uppermost_ion) - nne += (get_ionstage(element, ion) - 1) * ionstagepop(modelgridindex, element, ion); - } - } - } - - grid::set_nne(modelgridindex, nne); - grid::set_nnetot(modelgridindex, nne_tot); - return nne_tot; -} \ No newline at end of file diff --git a/update_grid.h b/update_grid.h index 826a303f0..c511db41e 100644 --- a/update_grid.h +++ b/update_grid.h @@ -6,9 +6,6 @@ void update_grid(FILE *estimators_file, int nts, int nts_prev, int my_rank, int nstart, int ndo, int titer, time_t real_time_start); -void precalculate_partfuncts(int modelgridindex); void cellhistory_reset(int modelgridindex, bool new_timestep); -double calculate_populations(int modelgridindex); -double calculate_electron_densities(int modelgridindex); #endif // UPDATE_GRID_H diff --git a/update_packets.cc b/update_packets.cc index bd905a504..9002d3a62 100644 --- a/update_packets.cc +++ b/update_packets.cc @@ -63,11 +63,11 @@ static void do_nonthermal_predeposit(struct packet *pkt_ptr, const int nts, cons // absorption happens if (pkt_ptr->pellet_decaytype == decay::DECAYTYPE_ALPHA) { - safeadd(globals::time_step[nts].alpha_dep, pkt_ptr->e_cmf); + safeadd(globals::timesteps[nts].alpha_dep, pkt_ptr->e_cmf); } else if (pkt_ptr->pellet_decaytype == decay::DECAYTYPE_BETAMINUS) { - safeadd(globals::time_step[nts].electron_dep, pkt_ptr->e_cmf); + safeadd(globals::timesteps[nts].electron_dep, pkt_ptr->e_cmf); } else if (pkt_ptr->pellet_decaytype == decay::DECAYTYPE_BETAPLUS) { - safeadd(globals::time_step[nts].positron_dep, pkt_ptr->e_cmf); + safeadd(globals::timesteps[nts].positron_dep, pkt_ptr->e_cmf); } pkt_ptr->type = TYPE_NTLEPTON; @@ -90,7 +90,7 @@ static void update_pellet(struct packet *pkt_ptr, const int nts, const double t2 // That's all that needs to be done for the inactive pellet. } else if (tdecay > ts) { // The packet decays in the current timestep. - safeincrement(globals::time_step[nts].pellet_decays); + globals::timesteps[nts].pellet_decays++; pkt_ptr->prop_time = tdecay; vec_scale(pkt_ptr->pos, tdecay / ts); @@ -98,22 +98,22 @@ static void update_pellet(struct packet *pkt_ptr, const int nts, const double t2 if (pkt_ptr->originated_from_particlenotgamma) // will decay to non-thermal particle { if (pkt_ptr->pellet_decaytype == decay::DECAYTYPE_BETAPLUS) { - safeadd(globals::time_step[nts].positron_dep, pkt_ptr->e_cmf); + safeadd(globals::timesteps[nts].positron_dep, pkt_ptr->e_cmf); pkt_ptr->type = TYPE_NTLEPTON; pkt_ptr->absorptiontype = -10; } else if (pkt_ptr->pellet_decaytype == decay::DECAYTYPE_BETAMINUS) { - safeadd(globals::time_step[nts].electron_emission, pkt_ptr->e_cmf); + safeadd(globals::timesteps[nts].electron_emission, pkt_ptr->e_cmf); pkt_ptr->em_time = pkt_ptr->prop_time; pkt_ptr->type = TYPE_NONTHERMAL_PREDEPOSIT; pkt_ptr->absorptiontype = -10; } else if (pkt_ptr->pellet_decaytype == decay::DECAYTYPE_ALPHA) { - safeadd(globals::time_step[nts].alpha_emission, pkt_ptr->e_cmf); + safeadd(globals::timesteps[nts].alpha_emission, pkt_ptr->e_cmf); pkt_ptr->em_time = pkt_ptr->prop_time; pkt_ptr->type = TYPE_NONTHERMAL_PREDEPOSIT; pkt_ptr->absorptiontype = -10; } } else { - safeadd(globals::time_step[nts].gamma_emission, pkt_ptr->e_cmf); + safeadd(globals::timesteps[nts].gamma_emission, pkt_ptr->e_cmf); // decay to gamma-ray, kpkt, or ntlepton gammapkt::pellet_gamma_decay(pkt_ptr); } @@ -152,7 +152,7 @@ static void do_packet(struct packet *const pkt_ptr, const double t2, const int n gammapkt::do_gamma(pkt_ptr, t2); if (pkt_ptr->type != TYPE_GAMMA && pkt_ptr->type != TYPE_ESCAPE) { - safeadd(globals::time_step[nts].gamma_dep, pkt_ptr->e_cmf); + safeadd(globals::timesteps[nts].gamma_dep, pkt_ptr->e_cmf); } break; } @@ -161,7 +161,7 @@ static void do_packet(struct packet *const pkt_ptr, const double t2, const int n do_rpkt(pkt_ptr, t2); if (pkt_ptr->type == TYPE_ESCAPE) { - safeadd(globals::time_step[nts].cmf_lum, pkt_ptr->e_cmf); + safeadd(globals::timesteps[nts].cmf_lum, pkt_ptr->e_cmf); } break; } @@ -177,13 +177,13 @@ static void do_packet(struct packet *const pkt_ptr, const double t2, const int n } case TYPE_PRE_KPKT: { - kpkt::do_kpkt_bb(pkt_ptr); + kpkt::do_kpkt_blackbody(pkt_ptr); break; } case TYPE_KPKT: { if (grid::modelgrid[grid::get_cell_modelgridindex(pkt_ptr->where)].thick == 1) { - kpkt::do_kpkt_bb(pkt_ptr); + kpkt::do_kpkt_blackbody(pkt_ptr); } else { kpkt::do_kpkt(pkt_ptr, t2, nts); } @@ -250,8 +250,8 @@ void update_packets(const int my_rank, const int nts, struct packet *packets) // matter. Those that are photons (or one sort or another) will already have a position and // a direction. - const double ts = globals::time_step[nts].start; - const double tw = globals::time_step[nts].width; + const double ts = globals::timesteps[nts].start; + const double tw = globals::timesteps[nts].width; const time_t time_update_packets_start = time(nullptr); printout("timestep %d: start update_packets at time %ld\n", nts, time_update_packets_start); @@ -299,7 +299,8 @@ void update_packets(const int my_rank, const int nts, struct packet *packets) const int mgi = grid::get_cell_modelgridindex(cellindex); /// for non empty cells update the global available level populations and cooling terms /// Reset cellhistory if packet starts up in another than the last active cell - if (mgi != grid::get_npts_model() && globals::cellhistory[tid].cellnumber != mgi) { + if (mgi != grid::get_npts_model() && globals::cellhistory[tid].cellnumber != mgi && + grid::modelgrid[mgi].thick == 0) { stats::increment(stats::COUNTER_UPDATECELL); cellhistory_reset(mgi, false); } diff --git a/vectors.cc b/vectors.cc index 623c3cdb2..4b7fd03dc 100644 --- a/vectors.cc +++ b/vectors.cc @@ -1,13 +1,11 @@ #include "vectors.h" -// #include - #include #include "artisoptions.h" #include "sn3d.h" -void scatter_dir(const double dir_in[3], const double cos_theta, double dir_out[3]) +void scatter_dir(std::span dir_in, const double cos_theta, std::span dir_out) // Routine for scattering a direction through angle theta. { // begin with setting the direction in coordinates where original direction @@ -26,7 +24,7 @@ void scatter_dir(const double dir_in[3], const double cos_theta, double dir_out[ // Rotation matrix is determined by dir_in. const double norm1 = 1. / std::sqrt((dir_in[0] * dir_in[0]) + (dir_in[1] * dir_in[1])); - const double norm2 = 1. / std::sqrt((dir_in[0] * dir_in[0]) + (dir_in[1] * dir_in[1]) + (dir_in[2] * dir_in[2])); + const double norm2 = 1. / vec_len(dir_in); const double r11 = dir_in[1] * norm1; const double r12 = -1 * dir_in[0] * norm1; @@ -45,7 +43,7 @@ void scatter_dir(const double dir_in[3], const double cos_theta, double dir_out[ assert_testmodeonly(std::fabs(vec_len(dir_out) - 1.) < 1e-10); } -void get_rand_isotropic_unitvec(double vecout[3]) +void get_rand_isotropic_unitvec(std::span vecout) // Assuming isotropic distribution, get a random direction vector { // alternatively, use GSL's functions: diff --git a/vectors.h b/vectors.h index 078530a70..8b17aae12 100644 --- a/vectors.h +++ b/vectors.h @@ -1,23 +1,28 @@ #ifndef VECTORS_H #define VECTORS_H +#include #include +#include +#include #include "constants.h" #include "exspec.h" #include "packet.h" #include "sn3d.h" -void scatter_dir(const double dir_in[3], double cos_theta, double dir_out[3]); -void get_rand_isotropic_unitvec(double vecout[3]); +void scatter_dir(std::span dir_in, double cos_theta, std::span dir_out); +void get_rand_isotropic_unitvec(std::span vecout); -constexpr double vec_len(const double x[3]) +[[nodiscard]] [[gnu::pure]] constexpr auto vec_len(std::span vec) -> double // return the the magnitude of a vector { - return std::sqrt((x[0] * x[0]) + (x[1] * x[1]) + (x[2] * x[2])); + const double squaredlen = std::accumulate(vec.begin(), vec.end(), 0., [](auto a, auto b) { return a + b * b; }); + + return std::sqrt(squaredlen); } -constexpr void vec_norm(const double vec_in[3], double vec_out[3]) +constexpr void vec_norm(std::span vec_in, std::span vec_out) // normalizing a copy of vec_in and save it to vec_out { const double magnitude = vec_len(vec_in); @@ -29,13 +34,13 @@ constexpr void vec_norm(const double vec_in[3], double vec_out[3]) assert_testmodeonly(fabs(vec_len(vec_out) - 1.) < 1.e-10); } -constexpr double dot(const double x[3], const double y[3]) +[[nodiscard]] [[gnu::pure]] constexpr auto dot(std::span x, std::span y) -> double // vector dot product { - return (x[0] * y[0]) + (x[1] * y[1]) + (x[2] * y[2]); + return std::inner_product(x.begin(), x.end(), y.begin(), 0.); } -constexpr void get_velocity(const double x[3], double y[3], const double t) +constexpr void get_velocity(std::span x, std::span y, const double t) // Routine for getting velocity vector of the flow at a position with homologous expansion. { y[0] = x[0] / t; @@ -43,25 +48,26 @@ constexpr void get_velocity(const double x[3], double y[3], const double t) y[2] = x[2] / t; } -constexpr void cross_prod(const double vec1[3], const double vec2[3], double vecout[3]) { +constexpr void cross_prod(std::span vec1, std::span vec2, + std::span vecout) { vecout[0] = (vec1[1] * vec2[2]) - (vec2[1] * vec1[2]); vecout[1] = (vec1[2] * vec2[0]) - (vec2[2] * vec1[0]); vecout[2] = (vec1[0] * vec2[1]) - (vec2[0] * vec1[1]); } -constexpr void vec_scale(double vec[3], const double scalefactor) { +constexpr void vec_scale(std::span vec, const double scalefactor) { vec[0] *= scalefactor; vec[1] *= scalefactor; vec[2] *= scalefactor; } -constexpr void vec_copy(double destination[3], const double source[3]) { +constexpr void vec_copy(std::span destination, std::span source) { destination[0] = source[0]; destination[1] = source[1]; destination[2] = source[2]; } -constexpr void angle_ab(const double dir1[3], const double vel[3], double dir2[3]) +constexpr void angle_ab(std::span dir1, std::span vel, std::span dir2) // aberation of angles in special relativity // dir1: direction unit vector in frame1 // vel: velocity of frame2 relative to frame1 @@ -81,7 +87,8 @@ constexpr void angle_ab(const double dir1[3], const double vel[3], double dir2[3 vec_norm(dir2, dir2); } -constexpr double doppler_nucmf_on_nurf(const double dir_rf[3], const double vel_rf[3]) +[[gnu::pure]] [[nodiscard]] constexpr double doppler_nucmf_on_nurf(std::span dir_rf, + std::span vel_rf) // Doppler factor // arguments: // dir_rf: the rest frame direction (unit vector) of light propagation @@ -107,15 +114,22 @@ constexpr double doppler_nucmf_on_nurf(const double dir_rf[3], const double vel_ return dopplerfactor; } -constexpr double doppler_squared_nucmf_on_nurf(const double dir_rf[3], const double vel_rf[3]) +[[gnu::pure]] [[nodiscard]] constexpr double doppler_squared_nucmf_on_nurf(std::span pos_rf, + std::span dir_rf, + const double prop_time) // Doppler factor squared, either to first order v/c or fully relativisitic // depending on USE_RELATIVISTIC_DOPPLER_SHIFT // // arguments: +// pos_rf: the rest frame position of the packet // dir_rf: the rest frame direction (unit vector) of light propagation -// vel_rf: velocity of the comoving frame relative to the rest frame +// prop_time: the propagation time of the packet // returns: the ratio f = (nu_cmf / nu_rf) ^ 2 { + // velocity of the comoving frame relative to the rest frame + std::array vel_rf = {0, 0, 0}; // homologous flow velocity + get_velocity(pos_rf, vel_rf, prop_time); + assert_testmodeonly(dot(vel_rf, vel_rf) / CLIGHTSQUARED >= 0.); assert_testmodeonly(dot(vel_rf, vel_rf) / CLIGHTSQUARED < 1.); @@ -137,10 +151,12 @@ constexpr double doppler_squared_nucmf_on_nurf(const double dir_rf[3], const dou return dopplerfactorsq; } -constexpr double doppler_packet_nucmf_on_nurf(const struct packet *const pkt_ptr) { +[[gnu::pure]] [[nodiscard]] constexpr double doppler_packet_nucmf_on_nurf(std::span pos_rf, + std::span dir_rf, + const double prop_time) { double flow_velocity[3] = {0, 0, 0}; // homologous flow velocity - get_velocity(pkt_ptr->pos, flow_velocity, pkt_ptr->prop_time); - return doppler_nucmf_on_nurf(pkt_ptr->dir, flow_velocity); + get_velocity(pos_rf, flow_velocity, prop_time); + return doppler_nucmf_on_nurf(dir_rf, flow_velocity); } constexpr void move_pkt(struct packet *pkt_ptr, const double distance) @@ -156,7 +172,7 @@ constexpr void move_pkt(struct packet *pkt_ptr, const double distance) /// During motion, rest frame energy and frequency are conserved. /// But need to update the co-moving ones. - const double dopplerfactor = doppler_packet_nucmf_on_nurf(pkt_ptr); + const double dopplerfactor = doppler_packet_nucmf_on_nurf(pkt_ptr->pos, pkt_ptr->dir, pkt_ptr->prop_time); pkt_ptr->nu_cmf = pkt_ptr->nu_rf * dopplerfactor; pkt_ptr->e_cmf = pkt_ptr->e_rf * dopplerfactor; } @@ -171,12 +187,10 @@ constexpr void move_pkt_withtime(struct packet *pkt_ptr, const double distance) // frequency should only over decrease due to packet movement // enforce this to overcome numerical error - if (pkt_ptr->nu_cmf > nu_cmf_old) { - pkt_ptr->nu_cmf = nu_cmf_old; - } + pkt_ptr->nu_cmf = std::min(pkt_ptr->nu_cmf, nu_cmf_old); } -constexpr double get_arrive_time(const struct packet *pkt_ptr) +[[nodiscard]] [[gnu::pure]] constexpr double get_arrive_time(const struct packet *const pkt_ptr) /// We know that a packet escaped at "escape_time". However, we have /// to allow for travel time. Use the formula in Leon's paper. The extra /// distance to be travelled beyond the reference surface is ds = r_ref (1 - mu). @@ -188,26 +202,26 @@ inline double get_arrive_time_cmf(const struct packet *pkt_ptr) { return pkt_ptr->escape_time * std::sqrt(1. - (globals::vmax * globals::vmax / CLIGHTSQUARED)); } -constexpr int get_escapedirectionbin(const double dir_in[3], const double syn_dir[3]) { +constexpr int get_escapedirectionbin(std::span dir_in, std::span syn_dir) { constexpr double xhat[3] = {1.0, 0.0, 0.0}; // sometimes dir vectors aren't accurately normalised const double dirmag = vec_len(dir_in); - const double dir[3] = {dir_in[0] / dirmag, dir_in[1] / dirmag, dir_in[2] / dirmag}; + std::array dir = {dir_in[0] / dirmag, dir_in[1] / dirmag, dir_in[2] / dirmag}; /// Angle resolved case: need to work out the correct angle bin const double costheta = dot(dir, syn_dir); const int costhetabin = static_cast((costheta + 1.0) * NPHIBINS / 2.0); assert_testmodeonly(costhetabin < NCOSTHETABINS); - double vec1[3] = {0}; + std::array vec1 = {0}; cross_prod(dir, syn_dir, vec1); - double vec2[3] = {0}; + std::array vec2 = {0}; cross_prod(xhat, syn_dir, vec2); const double cosphi = dot(vec1, vec2) / vec_len(vec1) / vec_len(vec2); - double vec3[3] = {0}; + std::array vec3 = {0}; cross_prod(vec2, syn_dir, vec3); const double testphi = dot(vec1, vec3); diff --git a/vpkt.cc b/vpkt.cc index 62467e077..27d98c803 100644 --- a/vpkt.cc +++ b/vpkt.cc @@ -1,26 +1,34 @@ #include "vpkt.h" +#include + +#include #include +#include #include #include "atomic.h" -#include "boundary.h" #include "grid.h" #include "ltepop.h" #include "rpkt.h" #include "sn3d.h" +#include "stats.h" #include "update_grid.h" #include "vectors.h" +struct stokeparams { + double i = 0.; + double q = 0.; + double u = 0.; +}; + struct vspecpol { - double flux[VMNUBINS]; - float lower_time; - float delta_t; + struct stokeparams flux[VMNUBINS]; + float lower_time = NAN; + float delta_t = NAN; }; -struct vspecpol **vstokes_i; -struct vspecpol **vstokes_q; -struct vspecpol **vstokes_u; +struct vspecpol **vspecpol = nullptr; float lower_freq_vspec[VMNUBINS]; float delta_freq_vspec[VMNUBINS]; @@ -29,41 +37,43 @@ float delta_freq_vspec[VMNUBINS]; int Nobs; // Number of observer directions int Nspectra; // Number of virtual packet spectra per observer direction (total + elements switched off) -double *nz_obs_vpkt; -double *phiobs; -double tmin_vspec_input; -double tmax_vspec_input; -int Nrange; - -double numin_vspec_input[MRANGE]; -double numax_vspec_input[MRANGE]; +std::vector nz_obs_vpkt; +std::vector phiobs; +double VSPEC_TIMEMIN_input; +double VSPEC_TIMEMAX_input; +int Nrange; // Number of wavelength ranges + +std::vector VSPEC_NUMIN_input; +std::vector VSPEC_NUMAX_input; double cell_is_optically_thick_vpkt; double tau_max_vpkt; -double *exclude; -double *tau_vpkt; + +std::vector exclude; // vector of opacity contribution setups + //-1: no line opacity; -2: no bf opacity; -3: no ff opacity; -4: no es opacity, + // +ve: exclude element with atomic number's contribution to bound-bound opacity +std::vector tau_vpkt; // --------- Vstruct packet GRID ----------- struct vgrid { - double *flux[MRANGE_GRID]; - double *yvel[MRANGE_GRID]; - double *zvel[MRANGE_GRID]; + std::vector> flux; + double yvel = NAN; + double zvel = NAN; }; -struct vgrid vgrid_i[NY_VGRID][NZ_VGRID]; -struct vgrid vgrid_q[NY_VGRID][NZ_VGRID]; -struct vgrid vgrid_u[NY_VGRID][NZ_VGRID]; +struct vgrid vgrid_i[VGRID_NY][VGRID_NZ]; +struct vgrid vgrid_q[VGRID_NY][VGRID_NZ]; +struct vgrid vgrid_u[VGRID_NY][VGRID_NZ]; int Nrange_grid; double tmin_grid; double tmax_grid; -double nu_grid_min[MRANGE_GRID]; -double nu_grid_max[MRANGE_GRID]; -int vgrid_flag; -double dlogt_vspec; -double dlognu_vspec; +std::vector nu_grid_min; +std::vector nu_grid_max; +bool vgrid_on; -int realtype; +double dlogt_vspec = NAN; +double dlognu_vspec = NAN; // number of virtual packets in a given timestep int nvpkt; @@ -73,63 +83,92 @@ int nvpkt_esc1; // electron scattering event int nvpkt_esc2; // kpkt deactivation int nvpkt_esc3; // macroatom deactivation -void rlc_emiss_vpkt(struct packet *pkt_ptr, double t_current, int bin, double *obs, int realtype) { - double vel_vec[3]; - double old_dir_cmf[3]; - double obs_cmf[3]; - double vel_rev[3]; - double s_cont = NAN; - double kap_cont = NAN; - double kap_cont_nobf = NAN; - double kap_cont_noff = NAN; - double kap_cont_noes = NAN; +// Virtual packet is killed when tau reaches tau_max_vpkt for ALL the different setups +// E.g. imagine that a packet in the first setup (all elements included) reaches tau = tau_max_vpkt +// because of the element Zi. If we remove Zi, tau now could be lower than tau_max_vpkt and could +// thus contribute to the spectrum. +static auto all_taus_past_taumax(std::vector &tau, const double tau_max) -> bool { + return std::ranges::all_of(tau, [tau_max](const double tau_i) { return tau_i > tau_max; }); +} + +// Routine to add a packet to the outcoming spectrum. +static void add_to_vspecpol(const struct packet &vpkt, const int obsbin, const int ind, const double t_arrive) { + // Need to decide in which (1) time and (2) frequency bin the vpkt is escaping + + const int ind_comb = Nspectra * obsbin + ind; + + /// Put this into the time grid. + if (t_arrive > VSPEC_TIMEMIN && t_arrive < VSPEC_TIMEMAX) { + const int nt = static_cast((log(t_arrive) - log(VSPEC_TIMEMIN)) / dlogt_vspec); + if (vpkt.nu_rf > VSPEC_NUMIN && vpkt.nu_rf < VSPEC_NUMAX) { + const int nnu = static_cast((log(vpkt.nu_rf) - log(VSPEC_NUMIN)) / dlognu_vspec); + const double pktcontrib = vpkt.e_rf / vspecpol[nt][ind_comb].delta_t / delta_freq_vspec[nnu] / 4.e12 / PI / + PARSEC / PARSEC / globals::nprocs * 4 * PI; + + safeadd(vspecpol[nt][ind_comb].flux[nnu].i, vpkt.stokes[0] * pktcontrib); + safeadd(vspecpol[nt][ind_comb].flux[nnu].q, vpkt.stokes[1] * pktcontrib); + safeadd(vspecpol[nt][ind_comb].flux[nnu].u, vpkt.stokes[2] * pktcontrib); + } + } +} + +// Routine to add a packet to the outcoming spectrum. +static void add_to_vpkt_grid(const struct packet &vpkt, std::span vel, const int wlbin, + const int obsbin, std::span obs) { + double vref1 = NAN; + double vref2 = NAN; + + // obs is the observer orientation + + // Packet velocity + + // if nobs = x , vref1 = vy and vref2 = vz + if (obs[0] == 1) { + vref1 = vel[1]; + vref2 = vel[2]; + } + // if nobs = -x , vref1 = -vy and vref2 = -vz + else if (obs[0] == -1) { + vref1 = -vel[1]; + vref2 = -vel[2]; + } + + // Rotate velocity into projected area seen by the observer (see notes) + else { + // Rotate velocity from (x,y,z) to (n_obs,ref1,ref2) so that x correspond to n_obs (see notes) + vref1 = -obs[1] * vel[0] + (obs[0] + obs[2] * obs[2] / (1 + obs[0])) * vel[1] - + obs[1] * obs[2] * (1 - obs[0]) / sqrt(1 - obs[0] * obs[0]) * vel[2]; + vref2 = -obs[2] * vel[0] - obs[1] * obs[2] * (1 - obs[0]) / sqrt(1 - obs[0] * obs[0]) * vel[1] + + (obs[0] + obs[1] * obs[1] / (1 + obs[0])) * vel[2]; + } + + // Outside the grid + if (fabs(vref1) >= globals::vmax || fabs(vref2) >= globals::vmax) { + return; + } + + // Bin size + + // vgrid cell (can be different to propagation cell size) + const int ny = static_cast((globals::vmax - vref1) / (2 * globals::vmax / VGRID_NY)); + const int nz = static_cast((globals::vmax - vref2) / (2 * globals::vmax / VGRID_NZ)); + + // Add contribution + if (vpkt.nu_rf > nu_grid_min[wlbin] && vpkt.nu_rf < nu_grid_max[wlbin]) { + safeadd(vgrid_i[ny][nz].flux[wlbin][obsbin], vpkt.stokes[0] * vpkt.e_rf); + safeadd(vgrid_q[ny][nz].flux[wlbin][obsbin], vpkt.stokes[1] * vpkt.e_rf); + safeadd(vgrid_u[ny][nz].flux[wlbin][obsbin], vpkt.stokes[2] * vpkt.e_rf); + } +} + +static void rlc_emiss_vpkt(const struct packet *const pkt_ptr, const double t_current, const int obsbin, + std::span obsdir, const enum packet_type realtype) { int snext = 0; - double t_arrive = NAN; - int element = 0; - int ion = 0; - int upper = 0; - int lower = 0; - double A_ul = NAN; - double B_ul = NAN; - double B_lu = NAN; - double n_u = NAN; - double n_l = NAN; - double t_line = NAN; int mgi = 0; - double Qold = NAN; - double Uold = NAN; - double Inew = NAN; - double Qnew = NAN; - double Unew = NAN; - double Itmp = NAN; - double Qtmp = NAN; - double Utmp = NAN; - double I = NAN; - double Q = NAN; - double U = NAN; - double pn = NAN; - double prob = NAN; - double mu = NAN; - double i1 = NAN; - double i2 = NAN; - double cos2i1 = NAN; - double sin2i1 = NAN; - double cos2i2 = NAN; - double sin2i2 = NAN; - double ref1[3]; - double ref2[3]; - int anumber = 0; - int tau_flag = 0; - - int bin_range = 0; - - struct packet dummy; - dummy = *pkt_ptr; - struct packet *dummy_ptr = nullptr; - dummy_ptr = &dummy; + + struct packet vpkt = *pkt_ptr; bool end_packet = false; - double sdist = 0; double ldist = 0; double t_future = t_current; @@ -137,53 +176,64 @@ void rlc_emiss_vpkt(struct packet *pkt_ptr, double t_current, int bin, double *o tau_vpkt[ind] = 0; } - dummy_ptr->dir[0] = obs[0]; - dummy_ptr->dir[1] = obs[1]; - dummy_ptr->dir[2] = obs[2]; + vpkt.dir[0] = obsdir[0]; + vpkt.dir[1] = obsdir[1]; + vpkt.dir[2] = obsdir[2]; + vpkt.last_cross = BOUNDARY_NONE; safeincrement(nvpkt); // increment the number of virtual packet in the given timestep + double vel_vec[3] = {NAN, NAN, NAN}; get_velocity(pkt_ptr->pos, vel_vec, t_current); // rf frequency and energy - dummy_ptr->nu_rf = dummy_ptr->nu_cmf / doppler_nucmf_on_nurf(dummy_ptr->dir, vel_vec); - dummy_ptr->e_rf = dummy_ptr->e_cmf * dummy_ptr->nu_rf / dummy_ptr->nu_cmf; + const double dopplerfactor = doppler_nucmf_on_nurf(vpkt.dir, vel_vec); + vpkt.nu_rf = vpkt.nu_cmf / dopplerfactor; + vpkt.e_rf = vpkt.e_cmf / dopplerfactor; - double Qi = dummy_ptr->stokes[1]; - double Ui = dummy_ptr->stokes[2]; + double Qi = vpkt.stokes[1]; + double Ui = vpkt.stokes[2]; // ------------ SCATTERING EVENT: dipole function -------------------- - if (realtype == 1) { + double ref1[3] = {NAN, NAN, NAN}; + double ref2[3] = {NAN, NAN, NAN}; + double pn = NAN; + double I = NAN; + double Q = NAN; + double U = NAN; + if (realtype == TYPE_RPKT) { // Transform Stokes Parameters from the RF to the CMF + double old_dir_cmf[3] = {NAN, NAN, NAN}; frame_transform(pkt_ptr->dir, &Qi, &Ui, vel_vec, old_dir_cmf); // Need to rotate Stokes Parameters in the scattering plane - angle_ab(dummy_ptr->dir, vel_vec, obs_cmf); + double obs_cmf[3]; + angle_ab(vpkt.dir, vel_vec, obs_cmf); meridian(old_dir_cmf, ref1, ref2); // This is the i1 angle of Bulla+2015, obtained by computing the angle between the // reference axes ref1 and ref2 in the meridian frame and the corresponding axes // ref1_sc and ref2_sc in the scattering plane. - i1 = rot_angle(old_dir_cmf, obs_cmf, ref1, ref2); - cos2i1 = cos(2 * i1); - sin2i1 = sin(2 * i1); + const double i1 = rot_angle(old_dir_cmf, obs_cmf, ref1, ref2); + const double cos2i1 = cos(2 * i1); + const double sin2i1 = sin(2 * i1); - Qold = Qi * cos2i1 - Ui * sin2i1; - Uold = Qi * sin2i1 + Ui * cos2i1; + const double Qold = Qi * cos2i1 - Ui * sin2i1; + const double Uold = Qi * sin2i1 + Ui * cos2i1; // Scattering - mu = dot(old_dir_cmf, obs_cmf); + const double mu = dot(old_dir_cmf, obs_cmf); pn = 3. / (16. * PI) * (1 + pow(mu, 2.) + (pow(mu, 2.) - 1) * Qold); - Inew = 0.75 * ((mu * mu + 1.0) + Qold * (mu * mu - 1.0)); - Qnew = 0.75 * ((mu * mu - 1.0) + Qold * (mu * mu + 1.0)); - Unew = 1.5 * mu * Uold; + const double Inew = 0.75 * ((mu * mu + 1.0) + Qold * (mu * mu - 1.0)); + double Qnew = 0.75 * ((mu * mu - 1.0) + Qold * (mu * mu + 1.0)); + double Unew = 1.5 * mu * Uold; Qnew = Qnew / Inew; Unew = Unew / Inew; @@ -196,130 +246,124 @@ void rlc_emiss_vpkt(struct packet *pkt_ptr, double t_current, int bin, double *o // This is the i2 angle of Bulla+2015, obtained from the angle THETA between the // reference axes ref1_sc and ref2_sc in the scattering plane and ref1 and ref2 in the // meridian frame. NB: we need to add PI to transform THETA to i2 - i2 = PI + rot_angle(obs_cmf, old_dir_cmf, ref1, ref2); - cos2i2 = cos(2 * i2); - sin2i2 = sin(2 * i2); + const double i2 = PI + rot_angle(obs_cmf, old_dir_cmf, ref1, ref2); + const double cos2i2 = cos(2 * i2); + const double sin2i2 = sin(2 * i2); Q = Qnew * cos2i2 + Unew * sin2i2; U = -Qnew * sin2i2 + Unew * cos2i2; // Transform Stokes Parameters from the CMF to the RF - vel_rev[0] = -vel_vec[0]; - vel_rev[1] = -vel_vec[1]; - vel_rev[2] = -vel_vec[2]; + const double vel_rev[3] = {-vel_vec[0], -vel_vec[1], -vel_vec[2]}; - frame_transform(obs_cmf, &Q, &U, vel_rev, obs); - } - - // ------------ MACROATOM and KPKT: isotropic emission -------------------- + frame_transform(obs_cmf, &Q, &U, vel_rev, obsdir); - if (realtype == 2 || realtype == 3) { + } else if (realtype == TYPE_KPKT || realtype == TYPE_MA) { + // MACROATOM and KPKT: isotropic emission I = 1; Q = 0; U = 0; pn = 1 / (4 * PI); } - // --------- compute the optical depth to boundary ---------------- + // compute the optical depth to boundary - mgi = grid::get_cell_modelgridindex(dummy_ptr->where); + mgi = grid::get_cell_modelgridindex(vpkt.where); + struct rpkt_continuum_absorptioncoeffs chi_vpkt_cont = {}; while (!end_packet) { - ldist = 0; - // distance to the next cell - sdist = boundary_cross(dummy_ptr, &snext); - s_cont = sdist * t_current * t_current * t_current / (t_future * t_future * t_future); - - calculate_kappa_rpkt_cont(dummy_ptr, &globals::kappa_rpkt_cont[tid]); - - kap_cont = globals::kappa_rpkt_cont[tid].total; - kap_cont_nobf = kap_cont - globals::kappa_rpkt_cont[tid].bf; - kap_cont_noff = kap_cont - globals::kappa_rpkt_cont[tid].ff; - kap_cont_noes = kap_cont - globals::kappa_rpkt_cont[tid].es; - - for (int ind = 0; ind < Nspectra; ind++) { - if (exclude[ind] == -2) { - tau_vpkt[ind] += kap_cont_nobf * s_cont; - } else if (exclude[ind] == -3) { - tau_vpkt[ind] += kap_cont_noff * s_cont; - } else if (exclude[ind] == -4) { - tau_vpkt[ind] += kap_cont_noes * s_cont; - } else { - tau_vpkt[ind] += kap_cont * s_cont; - } - } - - // kill vpkt with high optical depth - tau_flag = check_tau(tau_vpkt, &tau_max_vpkt); - if (tau_flag == 0) { - return; - } + const double sdist = + grid::boundary_distance(vpkt.dir, vpkt.pos, vpkt.prop_time, vpkt.where, &snext, &vpkt.last_cross); + const double s_cont = sdist * t_current * t_current * t_current / (t_future * t_future * t_future); - while (ldist < sdist) { - // printout("next_trans = %d \t nutrans = %g \t",dummy_ptr->next_trans,nutrans); - - const int lineindex = closest_transition(dummy_ptr->nu_cmf, dummy_ptr->next_trans); - - const double nutrans = globals::linelist[lineindex].nu; - - if (lineindex >= 0) { - element = globals::linelist[lineindex].elementindex; - ion = globals::linelist[lineindex].ionindex; - upper = globals::linelist[lineindex].upperlevelindex; - lower = globals::linelist[lineindex].lowerlevelindex; - A_ul = globals::linelist[lineindex].einstein_A; - - anumber = get_atomicnumber(element); - - dummy_ptr->next_trans = lineindex + 1; - - if (dummy_ptr->nu_cmf < nutrans) { - ldist = 0; + if (mgi == grid::get_npts_model()) { + vpkt.next_trans = -1; + } else { + calculate_chi_rpkt_cont(vpkt.nu_cmf, &chi_vpkt_cont, mgi, false); + + const double chi_cont = chi_vpkt_cont.total; + + for (int ind = 0; ind < Nspectra; ind++) { + if (exclude[ind] == -2) { + const double chi_cont_nobf = chi_cont - chi_vpkt_cont.bf; + tau_vpkt[ind] += chi_cont_nobf * s_cont; + } else if (exclude[ind] == -3) { + const double chi_cont_noff = chi_cont - chi_vpkt_cont.ff; + tau_vpkt[ind] += chi_cont_noff * s_cont; + } else if (exclude[ind] == -4) { + const double chi_cont_noes = chi_cont - chi_vpkt_cont.es; + tau_vpkt[ind] += chi_cont_noes * s_cont; } else { - ldist = CLIGHT * t_current * (dummy_ptr->nu_cmf / nutrans - 1); + tau_vpkt[ind] += chi_cont * s_cont; } + } - if (ldist < 0.) { - printout("[warning] get_event: ldist < 0 %g\n", ldist); - } + // kill vpkt with high optical depth + if (all_taus_past_taumax(tau_vpkt, tau_max_vpkt)) { + return; + } - if (ldist > sdist) { /* exit the while loop if you reach the boundary; go back to the previous transition to - start next cell with the excluded line */ + struct packet dummypkt_abort = vpkt; + move_pkt_withtime(&dummypkt_abort, sdist); + const double nu_cmf_abort = dummypkt_abort.nu_cmf; + assert_testmodeonly(nu_cmf_abort <= vpkt.nu_cmf); + const double d_nu_on_d_l = (nu_cmf_abort - vpkt.nu_cmf) / sdist; - dummy_ptr->next_trans -= 1; - // printout("ldist > sdist : line in the next cell\n"); - break; - } + ldist = 0; + while (ldist < sdist) { + const int lineindex = closest_transition(vpkt.nu_cmf, vpkt.next_trans); + + if (lineindex < 0) { + vpkt.next_trans = globals::nlines + 1; + } else { + const double nutrans = globals::linelist[lineindex].nu; - t_line = t_current + ldist / CLIGHT; + vpkt.next_trans = lineindex + 1; - B_ul = CLIGHTSQUAREDOVERTWOH / pow(nutrans, 3) * A_ul; - B_lu = stat_weight(element, ion, upper) / stat_weight(element, ion, lower) * B_ul; + ldist = get_linedistance(t_current, vpkt.nu_cmf, nutrans, d_nu_on_d_l); - n_u = get_levelpop(mgi, element, ion, upper); - n_l = get_levelpop(mgi, element, ion, lower); + if (ldist > sdist) { + // exit the while loop if you reach the boundary; go back to the previous transition to start next cell with + // the excluded line - // Check on the element to exclude - // NB: ldist before need to be computed anyway (I want to move the packets to the - // line interaction point even if I don't interact) + vpkt.next_trans -= 1; + // printout("ldist > sdist : line in the next cell\n"); + break; + } - for (int ind = 0; ind < Nspectra; ind++) { - // If exclude[ind]==-1, I do not include line opacity - if (exclude[ind] != -1 && (anumber != exclude[ind])) { - tau_vpkt[ind] += (B_lu * n_l - B_ul * n_u) * HCLIGHTOVERFOURPI * t_line; + const double t_line = t_current + ldist / CLIGHT; + + const int element = globals::linelist[lineindex].elementindex; + const int ion = globals::linelist[lineindex].ionindex; + const int upper = globals::linelist[lineindex].upperlevelindex; + const int lower = globals::linelist[lineindex].lowerlevelindex; + const auto A_ul = globals::linelist[lineindex].einstein_A; + + const double B_ul = CLIGHTSQUAREDOVERTWOH / pow(nutrans, 3) * A_ul; + const double B_lu = stat_weight(element, ion, upper) / stat_weight(element, ion, lower) * B_ul; + + const auto n_u = calculate_levelpop(mgi, element, ion, upper); + const auto n_l = calculate_levelpop(mgi, element, ion, lower); + const double tau_line = (B_lu * n_l - B_ul * n_u) * HCLIGHTOVERFOURPI * t_line; + + // Check on the element to exclude + // NB: ldist before need to be computed anyway (I want to move the packets to the + // line interaction point even if I don't interact) + const int anumber = get_atomicnumber(element); + for (int ind = 0; ind < Nspectra; ind++) { + // If exclude[ind]==-1, I do not include line opacity + if (exclude[ind] != -1 && (exclude[ind] != anumber)) { + tau_vpkt[ind] += tau_line; + } } - } - /* kill vpkt with high optical depth */ - tau_flag = check_tau(tau_vpkt, &tau_max_vpkt); - if (tau_flag == 0) { - return; + // kill vpkt with high optical depth + if (all_taus_past_taumax(tau_vpkt, tau_max_vpkt)) { + return; + } } - } else { - dummy_ptr->next_trans = - globals::nlines + 1; /// helper variable to overcome numerical problems after line scattering } } @@ -328,169 +372,115 @@ void rlc_emiss_vpkt(struct packet *pkt_ptr, double t_current, int bin, double *o // printf("I'm changing cell. I'm going from nu_cmf = %.e ",dummy_ptr->nu_cmf); t_future += (sdist / CLIGHT_PROP); - dummy_ptr->prop_time = t_future; - move_pkt(dummy_ptr, sdist); + vpkt.prop_time = t_future; + move_pkt(&vpkt, sdist); - // printout("About to change vpkt cell\n"); - change_cell(dummy_ptr, snext); - end_packet = (dummy_ptr->type == TYPE_ESCAPE); - // printout("Completed change vpkt cell\n"); + grid::change_cell(&vpkt, snext); + end_packet = (vpkt.type == TYPE_ESCAPE); - // printout("dummy->nu_cmf = %g \n",dummy_ptr->nu_cmf); - mgi = grid::get_cell_modelgridindex(dummy_ptr->where); + mgi = grid::get_cell_modelgridindex(vpkt.where); // break if you reach an empty cell if (mgi == grid::get_npts_model()) { break; } - /* kill vpkt with pass through a thick cell */ - if (grid::modelgrid[mgi].thick == 1) { + // kill vpkt with pass through a thick cell + if (grid::modelgrid[mgi].thick != 0) { return; } } // increment the number of escaped virtual packet in the given timestep - if (realtype == 1) { + if (realtype == TYPE_RPKT) { safeincrement(nvpkt_esc1); - } else if (realtype == 2) { + } else if (realtype == TYPE_KPKT) { safeincrement(nvpkt_esc2); - } else if (realtype == 3) { + } else if (realtype == TYPE_MA) { safeincrement(nvpkt_esc3); } + const double t_arrive = t_current - (dot(pkt_ptr->pos, vpkt.dir) / CLIGHT_PROP); // -------------- final stokes vector --------------- for (int ind = 0; ind < Nspectra; ind++) { - // printout("bin %d spectrum %d tau_vpkt %g\n", bin, ind, tau_vpkt[ind]); - prob = pn * exp(-tau_vpkt[ind]); + // printout("obsbin %d spectrum %d tau_vpkt %g\n", obsbin, ind, tau_vpkt[ind]); + const double prob = pn * exp(-tau_vpkt[ind]); - Itmp = I * prob; - Qtmp = Q * prob; - Utmp = U * prob; + assert_always(std::isfinite(prob)); - dummy_ptr->stokes[0] = Itmp; - dummy_ptr->stokes[1] = Qtmp; - dummy_ptr->stokes[2] = Utmp; + vpkt.stokes[0] = I * prob; + vpkt.stokes[1] = Q * prob; + vpkt.stokes[2] = U * prob; - if (Itmp != Itmp || Qtmp != Qtmp || Utmp != Utmp) { - printout("Nan Number!! %g %g %g %g %g %g %g %g \n", Itmp, Qtmp, Utmp, pn, tau_vpkt[ind], mu, i1, i2); + for (const auto stokeval : vpkt.stokes) { + assert_always(std::isfinite(stokeval)); } // bin on fly and produce file with spectrum - t_arrive = t_current - (dot(pkt_ptr->pos, dummy_ptr->dir) / CLIGHT_PROP); - - add_to_vspecpol(dummy_ptr, bin, ind, t_arrive); + add_to_vspecpol(vpkt, obsbin, ind, t_arrive); } // vpkt grid - if (vgrid_flag == 1) { - prob = pn * exp(-tau_vpkt[0]); - - Itmp = I * prob; - Qtmp = Q * prob; - Utmp = U * prob; + if (vgrid_on) { + const double prob = pn * exp(-tau_vpkt[0]); - dummy_ptr->stokes[0] = Itmp; - dummy_ptr->stokes[1] = Qtmp; - dummy_ptr->stokes[2] = Utmp; + vpkt.stokes[0] = I * prob; + vpkt.stokes[1] = Q * prob; + vpkt.stokes[2] = U * prob; - for (bin_range = 0; bin_range < Nrange_grid; bin_range++) { - if (dummy_ptr->nu_rf > nu_grid_min[bin_range] && - dummy_ptr->nu_rf < nu_grid_max[bin_range]) { // Frequency selection - if (t_arrive > tmin_grid && t_arrive < tmax_grid) { // Time selection - add_to_vpkt_grid(dummy_ptr, vel_vec, bin_range, bin, obs); + for (int wlbin = 0; wlbin < Nrange_grid; wlbin++) { + if (vpkt.nu_rf > nu_grid_min[wlbin] && vpkt.nu_rf < nu_grid_max[wlbin]) { // Frequency selection + if (t_arrive > tmin_grid && t_arrive < tmax_grid) { // Time selection + add_to_vpkt_grid(vpkt, vel_vec, wlbin, obsbin, obsdir); } } } } } -// Virtual packet is killed when tau reaches tau_max_vpkt for ALL the different setups -// E.g. imagine that a packet in the first setup (all elements included) reaches tau = tau_max_vpkt -// because of the element Zi. If we remove Zi, tau now could be lower than tau_max_vpkt and could -// thus contribute to the spectrum. -auto check_tau(const double *tau, const double *tau_max) -> int { - int count = 0; - - for (int i = 0; i < Nspectra; i++) { - if (tau[i] > *tau_max) { - count += 1; - } - } - - if (count == Nspectra) { - return 0; - } - return 1; -} - -// Routine to add a packet to the outcoming spectrum. -void add_to_vspecpol(struct packet *pkt_ptr, int bin, int ind, double t_arrive) { - // Need to decide in which (1) time and (2) frequency bin the vpkt is escaping - - const int ind_comb = Nspectra * bin + ind; - - /// Put this into the time grid. - if (t_arrive > tmin_vspec && t_arrive < tmax_vspec) { - const int nt = static_cast((log(t_arrive) - log(tmin_vspec)) / dlogt_vspec); - if (pkt_ptr->nu_rf > numin_vspec && pkt_ptr->nu_rf < numax_vspec) { - const int nnu = static_cast((log(pkt_ptr->nu_rf) - log(numin_vspec)) / dlognu_vspec); - const double pktcontrib = pkt_ptr->e_rf / vstokes_i[nt][ind_comb].delta_t / delta_freq_vspec[nnu] / 4.e12 / PI / - PARSEC / PARSEC / globals::nprocs * 4 * PI; - - safeadd(vstokes_i[nt][ind_comb].flux[nnu], pkt_ptr->stokes[0] * pktcontrib); - safeadd(vstokes_q[nt][ind_comb].flux[nnu], pkt_ptr->stokes[1] * pktcontrib); - safeadd(vstokes_u[nt][ind_comb].flux[nnu], pkt_ptr->stokes[2] * pktcontrib); - } - } -} - -void init_vspecpol() { - vstokes_i = static_cast(malloc(VMTBINS * sizeof(struct vspecpol *))); - vstokes_q = static_cast(malloc(VMTBINS * sizeof(struct vspecpol *))); - vstokes_u = static_cast(malloc(VMTBINS * sizeof(struct vspecpol *))); +static void init_vspecpol() { + vspecpol = static_cast(malloc(VMTBINS * sizeof(struct vspecpol *))); const int indexmax = Nspectra * Nobs; for (int p = 0; p < VMTBINS; p++) { - vstokes_i[p] = static_cast(malloc(indexmax * sizeof(struct vspecpol))); - vstokes_q[p] = static_cast(malloc(indexmax * sizeof(struct vspecpol))); - vstokes_u[p] = static_cast(malloc(indexmax * sizeof(struct vspecpol))); + vspecpol[p] = static_cast(malloc(indexmax * sizeof(struct vspecpol))); } - for (int ind_comb = 0; ind_comb < indexmax; ind_comb++) { - // start by setting up the time and frequency bins. - // it is all done interms of a logarithmic spacing in both t and nu - get the - // step sizes first. - - dlogt_vspec = (log(tmax_vspec) - log(tmin_vspec)) / VMTBINS; - dlognu_vspec = (log(numax_vspec) - log(numin_vspec)) / VMNUBINS; - - for (int n = 0; n < VMTBINS; n++) { - vstokes_i[n][ind_comb].lower_time = exp(log(tmin_vspec) + (n * (dlogt_vspec))); - vstokes_i[n][ind_comb].delta_t = - exp(log(tmin_vspec) + ((n + 1) * (dlogt_vspec))) - vstokes_i[n][ind_comb].lower_time; + dlogt_vspec = (log(VSPEC_TIMEMAX) - log(VSPEC_TIMEMIN)) / VMTBINS; + dlognu_vspec = (log(VSPEC_NUMAX) - log(VSPEC_NUMIN)) / VMNUBINS; - for (int m = 0; m < VMNUBINS; m++) { - lower_freq_vspec[m] = exp(log(numin_vspec) + (m * (dlognu_vspec))); - delta_freq_vspec[m] = exp(log(numin_vspec) + ((m + 1) * (dlognu_vspec))) - lower_freq_vspec[m]; + for (int m = 0; m < VMNUBINS; m++) { + lower_freq_vspec[m] = exp(log(VSPEC_NUMIN) + (m * (dlognu_vspec))); + delta_freq_vspec[m] = exp(log(VSPEC_NUMIN) + ((m + 1) * (dlognu_vspec))) - lower_freq_vspec[m]; + } - vstokes_i[n][ind_comb].flux[m] = 0.0; - vstokes_q[n][ind_comb].flux[m] = 0.0; - vstokes_u[n][ind_comb].flux[m] = 0.0; + // start by setting up the time and frequency bins. + // it is all done interms of a logarithmic spacing in both t and nu - get the + // step sizes first. + for (int n = 0; n < VMTBINS; n++) { + for (int ind_comb = 0; ind_comb < indexmax; ind_comb++) { + vspecpol[n][ind_comb].lower_time = exp(log(VSPEC_TIMEMIN) + (n * (dlogt_vspec))); + vspecpol[n][ind_comb].delta_t = + exp(log(VSPEC_TIMEMIN) + ((n + 1) * (dlogt_vspec))) - vspecpol[n][ind_comb].lower_time; + + for (auto &flux : vspecpol[n][ind_comb].flux) { + flux.i = 0.0; + flux.q = 0.0; + flux.u = 0.0; } } } } -void write_vspecpol(FILE *specpol_file) { +static void write_vspecpol(FILE *specpol_file) { for (int ind_comb = 0; ind_comb < (Nobs * Nspectra); ind_comb++) { fprintf(specpol_file, "%g ", 0.); for (int l = 0; l < 3; l++) { for (int p = 0; p < VMTBINS; p++) { - fprintf(specpol_file, "%g ", (vstokes_i[p][ind_comb].lower_time + (vstokes_i[p][ind_comb].delta_t / 2.)) / DAY); + fprintf(specpol_file, "%g ", (vspecpol[p][ind_comb].lower_time + (vspecpol[p][ind_comb].delta_t / 2.)) / DAY); } } @@ -501,17 +491,17 @@ void write_vspecpol(FILE *specpol_file) { // Stokes I for (int p = 0; p < VMTBINS; p++) { - fprintf(specpol_file, "%g ", vstokes_i[p][ind_comb].flux[m]); + fprintf(specpol_file, "%g ", vspecpol[p][ind_comb].flux[m].i); } // Stokes Q for (int p = 0; p < VMTBINS; p++) { - fprintf(specpol_file, "%g ", vstokes_q[p][ind_comb].flux[m]); + fprintf(specpol_file, "%g ", vspecpol[p][ind_comb].flux[m].q); } // Stokes U for (int p = 0; p < VMTBINS; p++) { - fprintf(specpol_file, "%g ", vstokes_u[p][ind_comb].flux[m]); + fprintf(specpol_file, "%g ", vspecpol[p][ind_comb].flux[m].u); } fprintf(specpol_file, "\n"); @@ -519,38 +509,20 @@ void write_vspecpol(FILE *specpol_file) { } } -void read_vspecpol(int my_rank, int nts) { +static void read_vspecpol(int my_rank, int nts) { char filename[MAXFILENAMELENGTH]; - if (nts % 2 == 0) { - snprintf(filename, MAXFILENAMELENGTH, "vspecpol_%d_%d_odd.tmp", 0, my_rank); - } else { - snprintf(filename, MAXFILENAMELENGTH, "vspecpol_%d_%d_even.tmp", 0, my_rank); - } + snprintf(filename, MAXFILENAMELENGTH, "vspecpol_%d_%d_ts%d.tmp", 0, my_rank, nts); + printout("Reading vspecpol file %s\n", filename); - FILE *vspecpol_file = fopen_required(filename, "rb"); + FILE *vspecpol_file = fopen_required(filename, "r"); float a = NAN; float b = NAN; float c = NAN; for (int ind_comb = 0; ind_comb < (Nobs * Nspectra); ind_comb++) { - // Initialise times and frequencies - dlogt_vspec = (log(tmax_vspec) - log(tmin_vspec)) / VMTBINS; - dlognu_vspec = (log(numax_vspec) - log(numin_vspec)) / VMNUBINS; - - for (int n = 0; n < VMTBINS; n++) { - vstokes_i[n][ind_comb].lower_time = exp(log(tmin_vspec) + (n * (dlogt_vspec))); - vstokes_i[n][ind_comb].delta_t = - exp(log(tmin_vspec) + ((n + 1) * (dlogt_vspec))) - vstokes_i[n][ind_comb].lower_time; - - for (int m = 0; m < VMNUBINS; m++) { - lower_freq_vspec[m] = exp(log(numin_vspec) + (m * (dlognu_vspec))); - delta_freq_vspec[m] = exp(log(numin_vspec) + ((m + 1) * (dlognu_vspec))) - lower_freq_vspec[m]; - } - } - - // Initialise I,Q,U fluxes (from temporary files) + // Initialise I,Q,U fluxes from temporary files assert_always(fscanf(vspecpol_file, "%g ", &a) == 1); for (int l = 0; l < 3; l++) { @@ -566,17 +538,17 @@ void read_vspecpol(int my_rank, int nts) { // Stokes I for (int p = 0; p < VMTBINS; p++) { - assert_always(fscanf(vspecpol_file, "%lg ", &vstokes_i[p][ind_comb].flux[j]) == 1); + assert_always(fscanf(vspecpol_file, "%lg ", &vspecpol[p][ind_comb].flux[j].i) == 1); } // Stokes Q for (int p = 0; p < VMTBINS; p++) { - assert_always(fscanf(vspecpol_file, "%lg ", &vstokes_q[p][ind_comb].flux[j]) == 1); + assert_always(fscanf(vspecpol_file, "%lg ", &vspecpol[p][ind_comb].flux[j].q) == 1); } // Stokes U for (int p = 0; p < VMTBINS; p++) { - assert_always(fscanf(vspecpol_file, "%lg ", &vstokes_u[p][ind_comb].flux[j]) == 1); + assert_always(fscanf(vspecpol_file, "%lg ", &vspecpol[p][ind_comb].flux[j].u) == 1); } assert_always(fscanf(vspecpol_file, "\n") == 0); @@ -586,102 +558,47 @@ void read_vspecpol(int my_rank, int nts) { fclose(vspecpol_file); } -void init_vpkt_grid() { - const double ybin = 2 * globals::vmax / NY_VGRID; - const double zbin = 2 * globals::vmax / NZ_VGRID; - - for (int n = 0; n < NY_VGRID; n++) { - for (int m = 0; m < NZ_VGRID; m++) { - for (int bin_range = 0; bin_range < MRANGE_GRID; bin_range++) { - vgrid_i[n][m].flux[bin_range] = static_cast(malloc(Nobs * sizeof(double))); - vgrid_i[n][m].yvel[bin_range] = static_cast(malloc(Nobs * sizeof(double))); - vgrid_i[n][m].zvel[bin_range] = static_cast(malloc(Nobs * sizeof(double))); - - vgrid_q[n][m].flux[bin_range] = static_cast(malloc(Nobs * sizeof(double))); - vgrid_q[n][m].yvel[bin_range] = static_cast(malloc(Nobs * sizeof(double))); - vgrid_q[n][m].zvel[bin_range] = static_cast(malloc(Nobs * sizeof(double))); - - vgrid_u[n][m].flux[bin_range] = static_cast(malloc(Nobs * sizeof(double))); - vgrid_u[n][m].yvel[bin_range] = static_cast(malloc(Nobs * sizeof(double))); - vgrid_u[n][m].zvel[bin_range] = static_cast(malloc(Nobs * sizeof(double))); - - vgrid_i[n][m].flux[bin_range] = static_cast(malloc(Nobs * sizeof(double))); - for (int bin = 0; bin < Nobs; bin++) { - vgrid_i[n][m].flux[bin_range][bin] = 0.0; - vgrid_q[n][m].flux[bin_range][bin] = 0.0; - vgrid_u[n][m].flux[bin_range][bin] = 0.0; - - vgrid_i[n][m].yvel[bin_range][bin] = globals::vmax - (n + 0.5) * ybin; - vgrid_i[n][m].zvel[bin_range][bin] = globals::vmax - (m + 0.5) * zbin; - } - } - } - } -} - -// Routine to add a packet to the outcoming spectrum. -void add_to_vpkt_grid(struct packet *dummy_ptr, const double *vel, int bin_range, int bin, const double *obs) { - double vref1 = NAN; - double vref2 = NAN; - - // Observer orientation +static void init_vpkt_grid() { + const double ybin = 2 * globals::vmax / VGRID_NY; + const double zbin = 2 * globals::vmax / VGRID_NZ; - const double nx = obs[0]; - const double ny = obs[1]; - const double nz = obs[2]; + for (int n = 0; n < VGRID_NY; n++) { + for (int m = 0; m < VGRID_NZ; m++) { + const double yvel = globals::vmax - (n + 0.5) * ybin; + const double zvel = globals::vmax - (m + 0.5) * zbin; - // Packet velocity + vgrid_i[n][m].yvel = yvel; + vgrid_i[n][m].zvel = zvel; - /* if nobs = x , vref1 = vy and vref2 = vz */ - if (nx == 1) { - vref1 = vel[1]; - vref2 = vel[2]; - } - /* if nobs = x , vref1 = vy and vref2 = vz */ - else if (nx == -1) { - vref1 = -vel[1]; - vref2 = -vel[2]; - } + vgrid_q[n][m].yvel = yvel; + vgrid_q[n][m].zvel = zvel; - // Rotate velocity into projected area seen by the observer (see notes) - else { - // Rotate velocity from (x,y,z) to (n_obs,ref1,ref2) so that x correspond to n_obs (see notes) - vref1 = -ny * vel[0] + (nx + nz * nz / (1 + nx)) * vel[1] - ny * nz * (1 - nx) / sqrt(1 - nx * nx) * vel[2]; - vref2 = -nz * vel[0] - ny * nz * (1 - nx) / sqrt(1 - nx * nx) * vel[1] + (nx + ny * ny / (1 + nx)) * vel[2]; - } + vgrid_u[n][m].yvel = yvel; + vgrid_u[n][m].zvel = zvel; - // Outside the grid - if (fabs(vref1) >= globals::vmax || fabs(vref2) >= globals::vmax) { - return; - } - - // Bin size - const double ybin = 2 * globals::vmax / NY_VGRID; - const double zbin = 2 * globals::vmax / NZ_VGRID; - - // Grid cell - const int nt = static_cast((globals::vmax - vref1) / ybin); - const int mt = static_cast((globals::vmax - vref2) / zbin); - - // Add contribution - if (dummy_ptr->nu_rf > nu_grid_min[bin_range] && dummy_ptr->nu_rf < nu_grid_max[bin_range]) { - safeadd(vgrid_i[nt][mt].flux[bin_range][bin], dummy_ptr->stokes[0] * dummy_ptr->e_rf); - safeadd(vgrid_q[nt][mt].flux[bin_range][bin], dummy_ptr->stokes[1] * dummy_ptr->e_rf); - safeadd(vgrid_u[nt][mt].flux[bin_range][bin], dummy_ptr->stokes[2] * dummy_ptr->e_rf); + vgrid_i[n][m].flux.resize(Nrange_grid, {}); + vgrid_q[n][m].flux.resize(Nrange_grid, {}); + vgrid_u[n][m].flux.resize(Nrange_grid, {}); + for (int wlbin = 0; wlbin < Nrange_grid; wlbin++) { + vgrid_i[n][m].flux[wlbin] = std::vector(Nobs, 0.); + vgrid_q[n][m].flux[wlbin] = std::vector(Nobs, 0.); + vgrid_u[n][m].flux[wlbin] = std::vector(Nobs, 0.); + } + } } } -void write_vpkt_grid(FILE *vpkt_grid_file) { - for (int bin = 0; bin < Nobs; bin++) { - for (int bin_range = 0; bin_range < Nrange_grid; bin_range++) { - for (int n = 0; n < NY_VGRID; n++) { - for (int m = 0; m < NZ_VGRID; m++) { - fprintf(vpkt_grid_file, "%g ", vgrid_i[n][m].yvel[bin_range][bin]); - fprintf(vpkt_grid_file, "%g ", vgrid_i[n][m].zvel[bin_range][bin]); +static void write_vpkt_grid(FILE *vpkt_grid_file) { + for (int obsbin = 0; obsbin < Nobs; obsbin++) { + for (int wlbin = 0; wlbin < Nrange_grid; wlbin++) { + for (int n = 0; n < VGRID_NY; n++) { + for (int m = 0; m < VGRID_NZ; m++) { + fprintf(vpkt_grid_file, "%g ", vgrid_i[n][m].yvel); + fprintf(vpkt_grid_file, "%g ", vgrid_i[n][m].zvel); - fprintf(vpkt_grid_file, "%g ", vgrid_i[n][m].flux[bin_range][bin]); - fprintf(vpkt_grid_file, "%g ", vgrid_q[n][m].flux[bin_range][bin]); - fprintf(vpkt_grid_file, "%g ", vgrid_u[n][m].flux[bin_range][bin]); + fprintf(vpkt_grid_file, "%g ", vgrid_i[n][m].flux[wlbin][obsbin]); + fprintf(vpkt_grid_file, "%g ", vgrid_q[n][m].flux[wlbin][obsbin]); + fprintf(vpkt_grid_file, "%g ", vgrid_u[n][m].flux[wlbin][obsbin]); fprintf(vpkt_grid_file, "\n"); } @@ -690,23 +607,47 @@ void write_vpkt_grid(FILE *vpkt_grid_file) { } } -void read_vpkt_grid(FILE *vpkt_grid_file) { - for (int bin = 0; bin < Nobs; bin++) { - for (int bin_range = 0; bin_range < Nrange_grid; bin_range++) { - for (int n = 0; n < NY_VGRID; n++) { - for (int m = 0; m < NZ_VGRID; m++) { - assert_always(fscanf(vpkt_grid_file, "%lg ", &vgrid_i[n][m].yvel[bin_range][bin]) == 1); - assert_always(fscanf(vpkt_grid_file, "%lg ", &vgrid_i[n][m].zvel[bin_range][bin]) == 1); +static void read_vpkt_grid(const int my_rank, const int nts) { + if (!vgrid_on) { + return; + } + + char filename[MAXFILENAMELENGTH]; + snprintf(filename, MAXFILENAMELENGTH, "vpkt_grid_%d_%d_ts%d.tmp", 0, my_rank, nts); + printout("Reading vpkt grid file %s\n", filename); + FILE *vpkt_grid_file = fopen_required(filename, "r"); + + for (int obsbin = 0; obsbin < Nobs; obsbin++) { + for (int wlbin = 0; wlbin < Nrange_grid; wlbin++) { + for (int n = 0; n < VGRID_NY; n++) { + for (int m = 0; m < VGRID_NZ; m++) { + assert_always(fscanf(vpkt_grid_file, "%lg ", &vgrid_i[n][m].yvel) == 1); + assert_always(fscanf(vpkt_grid_file, "%lg ", &vgrid_i[n][m].zvel) == 1); - assert_always(fscanf(vpkt_grid_file, "%lg ", &vgrid_i[n][m].flux[bin_range][bin]) == 1); - assert_always(fscanf(vpkt_grid_file, "%lg ", &vgrid_q[n][m].flux[bin_range][bin]) == 1); - assert_always(fscanf(vpkt_grid_file, "%lg ", &vgrid_u[n][m].flux[bin_range][bin]) == 1); + assert_always(fscanf(vpkt_grid_file, "%lg ", &vgrid_i[n][m].flux[wlbin][obsbin]) == 1); + assert_always(fscanf(vpkt_grid_file, "%lg ", &vgrid_q[n][m].flux[wlbin][obsbin]) == 1); + assert_always(fscanf(vpkt_grid_file, "%lg ", &vgrid_u[n][m].flux[wlbin][obsbin]) == 1); assert_always(fscanf(vpkt_grid_file, "\n") == 0); } } } } + + fclose(vpkt_grid_file); +} + +void vpkt_remove_temp_file(const int nts, const int my_rank) { + char filenames[2][MAXFILENAMELENGTH]; + snprintf(filenames[0], MAXFILENAMELENGTH, "vspecpol_%d_%d_ts%d.tmp", 0, my_rank, nts); + snprintf(filenames[1], MAXFILENAMELENGTH, "vpkt_grid_%d_%d_ts%d.tmp", 0, my_rank, nts); + + for (auto &filename : filenames) { + if (access(filename, F_OK) == 0) { + remove(filename); + printout("Deleted %s\n", filename); + } + } } void read_parameterfile_vpkt() { @@ -718,7 +659,7 @@ void read_parameterfile_vpkt() { printout("vpkt.txt: Nobs %d directions\n", Nobs); // nz_obs_vpkt. Cos(theta) to the observer. A list in the case of many observers - nz_obs_vpkt = static_cast(malloc(Nobs * sizeof(double))); + nz_obs_vpkt.resize(Nobs); for (int i = 0; i < Nobs; i++) { assert_always(fscanf(input_file, "%lg", &nz_obs_vpkt[i]) == 1); @@ -733,13 +674,15 @@ void read_parameterfile_vpkt() { } // phi to the observer (degrees). A list in the case of many observers - phiobs = static_cast(malloc(Nobs * sizeof(double))); + phiobs.resize(Nobs); for (int i = 0; i < Nobs; i++) { double phi_degrees = 0.; assert_always(fscanf(input_file, "%lg \n", &phi_degrees) == 1); phiobs[i] = phi_degrees * PI / 180.; + const double theta_degrees = std::acos(nz_obs_vpkt[i]) / PI * 180.; - printout("vpkt.txt: direction %d costheta %g phi %g (%g degrees)\n", i, nz_obs_vpkt[i], phiobs[i], phi_degrees); + printout("vpkt.txt: direction %d costheta %g (%.1f degrees) phi %g (%.1f degrees)\n", i, nz_obs_vpkt[i], + theta_degrees, phiobs[i], phi_degrees); } // Nspectra opacity choices (i.e. Nspectra spectra for each observer) @@ -748,15 +691,15 @@ void read_parameterfile_vpkt() { if (nspectra_customlist_flag != 1) { Nspectra = 1; - exclude = static_cast(malloc(Nspectra * sizeof(double))); + exclude.resize(Nspectra, 0); exclude[0] = 0; } else { assert_always(fscanf(input_file, "%d ", &Nspectra) == 1); - exclude = static_cast(malloc(Nspectra * sizeof(double))); + exclude.resize(Nspectra, 0); for (int i = 0; i < Nspectra; i++) { - assert_always(fscanf(input_file, "%lg ", &exclude[i]) == 1); + assert_always(fscanf(input_file, "%d ", &exclude[i]) == 1); // The first number should be equal to zero! assert_always(exclude[0] == 0); // The first spectrum should allow for all opacities (exclude[i]=0) @@ -764,7 +707,7 @@ void read_parameterfile_vpkt() { } printout("vpkt.txt: Nspectra %d per observer\n", Nspectra); - tau_vpkt = static_cast(malloc(Nspectra * sizeof(double))); + tau_vpkt.resize(Nspectra, 0.); // time window. If dum4=1 it restrict vpkt to time windown (dum5,dum6) int override_tminmax = 0; @@ -772,22 +715,24 @@ void read_parameterfile_vpkt() { double vspec_tmax_in_days = 0.; assert_always(fscanf(input_file, "%d %lg %lg \n", &override_tminmax, &vspec_tmin_in_days, &vspec_tmax_in_days) == 3); - printout("vpkt: compiled with tmin_vspec %.1fd tmax_vspec %1.fd VMTBINS %d\n", tmin_vspec / DAY, tmax_vspec / DAY, - VMTBINS); + printout("vpkt: compiled with VSPEC_TIMEMIN %.1fd VSPEC_TIMEMAX %1.fd VMTBINS %d\n", VSPEC_TIMEMIN / DAY, + VSPEC_TIMEMAX / DAY, VMTBINS); if (override_tminmax == 1) { - tmin_vspec_input = vspec_tmin_in_days * DAY; - tmax_vspec_input = vspec_tmax_in_days * DAY; - printout("vpkt.txt: tmin_vspec_input %.1fd, tmax_vspec_input %.1fd\n", tmin_vspec_input / DAY, - tmax_vspec_input / DAY); + VSPEC_TIMEMIN_input = vspec_tmin_in_days * DAY; + VSPEC_TIMEMAX_input = vspec_tmax_in_days * DAY; + printout("vpkt.txt: VSPEC_TIMEMIN_input %.1fd, VSPEC_TIMEMAX_input %.1fd\n", VSPEC_TIMEMIN_input / DAY, + VSPEC_TIMEMAX_input / DAY); } else { - tmin_vspec_input = tmin_vspec; - tmax_vspec_input = tmax_vspec; - printout("vpkt.txt: tmin_vspec_input %.1fd, tmax_vspec_input %.1fd (inherited from tmin_vspec and tmax_vspec)\n", - tmin_vspec_input / DAY, tmax_vspec_input / DAY); + VSPEC_TIMEMIN_input = VSPEC_TIMEMIN; + VSPEC_TIMEMAX_input = VSPEC_TIMEMAX; + printout( + "vpkt.txt: VSPEC_TIMEMIN_input %.1fd, VSPEC_TIMEMAX_input %.1fd (inherited from VSPEC_TIMEMIN and " + "VSPEC_TIMEMAX)\n", + VSPEC_TIMEMIN_input / DAY, VSPEC_TIMEMAX_input / DAY); } - assert_always(tmin_vspec_input >= tmin_vspec); - assert_always(tmax_vspec_input <= tmax_vspec); + assert_always(VSPEC_TIMEMIN_input >= VSPEC_TIMEMIN); + assert_always(VSPEC_TIMEMAX_input <= VSPEC_TIMEMAX); // frequency window. dum4 restrict vpkt to a frequency range, dum5 indicates the number of ranges, // followed by a list of ranges (dum6,dum7) @@ -795,12 +740,14 @@ void read_parameterfile_vpkt() { assert_always(fscanf(input_file, "%d ", &flag_custom_freq_ranges) == 1); printout("vpkt: compiled with VMNUBINS %d\n", VMNUBINS); - assert_always(numax_vspec > numin_vspec); - printout("vpkt: compiled with numax_vspec %g lambda_min %g Å\n", numax_vspec, 1e8 * CLIGHT / numax_vspec); - printout("vpkt: compiled with numin_vspec %g lambda_max %g Å\n", numin_vspec, 1e8 * CLIGHT / numin_vspec); + assert_always(VSPEC_NUMAX > VSPEC_NUMIN); + printout("vpkt: compiled with VSPEC_NUMAX %g lambda_min %g Å\n", VSPEC_NUMAX, 1e8 * CLIGHT / VSPEC_NUMAX); + printout("vpkt: compiled with VSPEC_NUMIN %g lambda_max %g Å\n", VSPEC_NUMIN, 1e8 * CLIGHT / VSPEC_NUMIN); + if (flag_custom_freq_ranges == 1) { assert_always(fscanf(input_file, "%d ", &Nrange) == 1); - assert_always(Nrange <= MRANGE); + VSPEC_NUMIN_input.resize(Nrange, 0.); + VSPEC_NUMAX_input.resize(Nrange, 0.); printout("vpkt.txt: Nrange %d frequency intervals per spectrum per observer\n", Nrange); @@ -809,21 +756,21 @@ void read_parameterfile_vpkt() { double lmax_vspec_input = 0.; assert_always(fscanf(input_file, "%lg %lg", &lmin_vspec_input, &lmax_vspec_input) == 2); - numin_vspec_input[i] = CLIGHT / (lmax_vspec_input * 1e-8); - numax_vspec_input[i] = CLIGHT / (lmin_vspec_input * 1e-8); - printout("vpkt.txt: range %d lambda [%g, %g] Angstroms\n", i, 1e8 * CLIGHT / numax_vspec_input[i], - 1e8 * CLIGHT / numin_vspec_input[i]); + VSPEC_NUMIN_input[i] = CLIGHT / (lmax_vspec_input * 1e-8); + VSPEC_NUMAX_input[i] = CLIGHT / (lmin_vspec_input * 1e-8); } } else { Nrange = 1; - numin_vspec_input[0] = numin_vspec; - numax_vspec_input[0] = numax_vspec; + VSPEC_NUMIN_input.push_back(VSPEC_NUMIN); + VSPEC_NUMAX_input.push_back(VSPEC_NUMAX); - printout("vpkt.txt: Nrange 1 frequency interval (inherited from numin_vspec and numax_vspec)\n"); - const int i = 0; - printout("vpkt.txt: range %d lambda [%g, %g] Angstroms\n", i, 1e8 * CLIGHT / numax_vspec_input[i], - 1e8 * CLIGHT / numin_vspec_input[i]); + printout("vpkt.txt: Nrange 1 frequency interval (inherited from VSPEC_NUMIN and VSPEC_NUMAX)\n"); + } + + for (int i = 0; i < Nrange; i++) { + printout("vpkt.txt: range %d lambda [%g, %g] Angstroms\n", i, 1e8 * CLIGHT / VSPEC_NUMAX_input[i], + 1e8 * CLIGHT / VSPEC_NUMIN_input[i]); } // if dum7=1, vpkt are not created when cell optical depth is larger than cell_is_optically_thick_vpkt @@ -843,10 +790,12 @@ void read_parameterfile_vpkt() { printout("vpkt.txt: tau_max_vpkt %g\n", tau_max_vpkt); // Produce velocity grid map if =1 - assert_always(fscanf(input_file, "%d \n", &vgrid_flag) == 1); - printout("vpkt.txt: velocity grid map %s\n", (vgrid_flag == 1) ? "ENABLED" : "DISABLED"); + int in_vgrid_on = 0; + assert_always(fscanf(input_file, "%d \n", &in_vgrid_on) == 1); + vgrid_on = in_vgrid_on != 0; + printout("vpkt.txt: velocity grid map %s\n", (vgrid_on) ? "ENABLED" : "DISABLED"); - if (vgrid_flag == 1) { + if (vgrid_on) { double tmin_grid_in_days = NAN; double tmax_grid_in_days = NAN; // Specify time range for velocity grid map @@ -861,8 +810,8 @@ void read_parameterfile_vpkt() { printout("vpkt.txt: velocity grid frequency intervals %d\n", Nrange_grid); - assert_always(Nrange_grid <= MRANGE_GRID); - + nu_grid_max.resize(Nrange_grid, 0.); + nu_grid_min.resize(Nrange_grid, 0.); for (int i = 0; i < Nrange_grid; i++) { double range_lambda_min = 0.; double range_lambda_max = 0.; @@ -879,22 +828,78 @@ void read_parameterfile_vpkt() { fclose(input_file); } -auto vpkt_call_estimators(struct packet *pkt_ptr, double t_current, int realtype) -> int { - double obs[3]; - int vflag = 0; +void vpkt_write_timestep(const int nts, const int my_rank, const int tid, + const bool is_final) { // write specpol of the virtual packets + if constexpr (!VPKT_ON) { + return; + } - double vel_vec[3]; - get_velocity(pkt_ptr->pos, vel_vec, t_current); + char filename[MAXFILENAMELENGTH]; + + if (is_final) { + snprintf(filename, MAXFILENAMELENGTH, "vspecpol_%d-%d.out", my_rank, tid); + } else { + snprintf(filename, MAXFILENAMELENGTH, "vspecpol_%d_%d_ts%d.tmp", 0, my_rank, nts); + } + + printout("Writing vspecpol file %s\n", filename); + FILE *vspecpol_file = fopen_required(filename, "w"); + write_vspecpol(vspecpol_file); + fclose(vspecpol_file); + + if (vgrid_on) { + if (is_final) { + snprintf(filename, MAXFILENAMELENGTH, "vpkt_grid_%d-%d.out", my_rank, tid); + } else { + snprintf(filename, MAXFILENAMELENGTH, "vpkt_grid_%d_%d_ts%d.tmp", 0, my_rank, nts); + } + + printout("Writing vpkt grid file %s\n", filename); + FILE *vpkt_grid_file = fopen_required(filename, "w"); + write_vpkt_grid(vpkt_grid_file); + fclose(vpkt_grid_file); + } +} + +void vpkt_init(const int nts, const int my_rank, const int tid, const bool continued_from_saved) { + if constexpr (!VPKT_ON) { + return; + } + + init_vspecpol(); + if (vgrid_on) { + init_vpkt_grid(); + } + + if (continued_from_saved) { + // Continue simulation: read into temporary files + + read_vspecpol(my_rank, nts); + + if (vgrid_on) { + read_vpkt_grid(my_rank, nts); + } + } +} + +auto vpkt_call_estimators(struct packet *pkt_ptr, const enum packet_type realtype) -> void { + if constexpr (!VPKT_ON) { + return; + } // Cut on vpkts - int mgi = grid::get_cell_modelgridindex(pkt_ptr->where); + const int mgi = grid::get_cell_modelgridindex(pkt_ptr->where); if (grid::modelgrid[mgi].thick != 0) { - return 0; + return; } - /* this is just to find the next_trans value when is set to 0 (avoid doing that in the vpkt routine for each observer) - */ + const double t_current = pkt_ptr->prop_time; + + double vel_vec[3]; + get_velocity(pkt_ptr->pos, vel_vec, pkt_ptr->prop_time); + + // this is just to find the next_trans value when is set to 0 (avoid doing that in the vpkt routine for each observer) if (pkt_ptr->next_trans == 0) { const int lineindex = closest_transition(pkt_ptr->nu_cmf, pkt_ptr->next_trans); /// returns negative if (lineindex < 0) { @@ -902,60 +907,45 @@ auto vpkt_call_estimators(struct packet *pkt_ptr, double t_current, int realtype } } - for (int bin = 0; bin < Nobs; bin++) { - /* loop over different observers */ + for (int obsbin = 0; obsbin < Nobs; obsbin++) { + // loop over different observer directions - obs[0] = sqrt(1 - nz_obs_vpkt[bin] * nz_obs_vpkt[bin]) * cos(phiobs[bin]); - obs[1] = sqrt(1 - nz_obs_vpkt[bin] * nz_obs_vpkt[bin]) * sin(phiobs[bin]); - obs[2] = nz_obs_vpkt[bin]; + double obsdir[3] = {sqrt(1 - nz_obs_vpkt[obsbin] * nz_obs_vpkt[obsbin]) * cos(phiobs[obsbin]), + sqrt(1 - nz_obs_vpkt[obsbin] * nz_obs_vpkt[obsbin]) * sin(phiobs[obsbin]), nz_obs_vpkt[obsbin]}; - const double t_arrive = t_current - (dot(pkt_ptr->pos, obs) / CLIGHT_PROP); + const double t_arrive = t_current - (dot(pkt_ptr->pos, obsdir) / CLIGHT_PROP); - if (t_arrive >= tmin_vspec_input && t_arrive <= tmax_vspec_input) { + if (t_arrive >= VSPEC_TIMEMIN_input && t_arrive <= VSPEC_TIMEMAX_input) { // time selection + const double nu_rf = pkt_ptr->nu_cmf / doppler_nucmf_on_nurf(obsdir, vel_vec); + for (int i = 0; i < Nrange; i++) { // Loop over frequency ranges - if (pkt_ptr->nu_cmf / doppler_nucmf_on_nurf(obs, vel_vec) > numin_vspec_input[i] && - pkt_ptr->nu_cmf / doppler_nucmf_on_nurf(obs, vel_vec) < numax_vspec_input[i]) { + if (nu_rf > VSPEC_NUMIN_input[i] && nu_rf < VSPEC_NUMAX_input[i]) { // frequency selection - rlc_emiss_vpkt(pkt_ptr, t_current, bin, obs, realtype); - - vflag = 1; - - // Need to update the starting cell for next observer - // If previous vpkt reached tau_lim, change_cell (and then update_cell) hasn't been called - mgi = grid::get_cell_modelgridindex(pkt_ptr->where); - cellhistory_reset(mgi, false); + rlc_emiss_vpkt(pkt_ptr, t_current, obsbin, obsdir, realtype); } } } } - - // we just used the opacity variables for v-packets. We need to reset them for the original r packet - calculate_kappa_rpkt_cont(pkt_ptr, &globals::kappa_rpkt_cont[tid]); - - return vflag; } -auto rot_angle(double *n1, double *n2, double *ref1, double *ref2) -> double { - /* ------------- Rotation angle from the scattering plane --------------------------------------------- */ - /* -------- We need to rotate Stokes Parameters to (or from) the scattering plane from (or to) -------- */ - /* -------- the meridian frame such that Q=1 is in the scattering plane and along ref1 ---------------- */ - - double i = 0; +auto rot_angle(std::span n1, std::span n2, std::span ref1, std::span ref2) + -> double { + // Rotation angle from the scattering plane + // We need to rotate Stokes Parameters to (or from) the scattering plane from (or to) + // the meridian frame such that Q=1 is in the scattering plane and along ref1 - double ref1_sc[3]; // ref1_sc is the ref1 axis in the scattering plane ref1 = n1 x ( n1 x n2 ) - ref1_sc[0] = n1[0] * dot(n1, n2) - n2[0]; - ref1_sc[1] = n1[1] * dot(n1, n2) - n2[1]; - ref1_sc[2] = n1[2] * dot(n1, n2) - n2[2]; + const double n1_dot_n2 = dot(n1, n2); + double ref1_sc[3] = {n1[0] * n1_dot_n2 - n2[0], n1[1] * n1_dot_n2 - n2[1], n1[2] * n1_dot_n2 - n2[2]}; vec_norm(ref1_sc, ref1_sc); double cos_stokes_rot_1 = dot(ref1_sc, ref1); - double const cos_stokes_rot_2 = dot(ref1_sc, ref2); + const double cos_stokes_rot_2 = dot(ref1_sc, ref2); if (cos_stokes_rot_1 < -1) { cos_stokes_rot_1 = -1; @@ -964,20 +954,18 @@ auto rot_angle(double *n1, double *n2, double *ref1, double *ref2) -> double { cos_stokes_rot_1 = 1; } + double i = 0; if ((cos_stokes_rot_1 > 0) && (cos_stokes_rot_2 > 0)) { i = acos(cos_stokes_rot_1); - } - if ((cos_stokes_rot_1 > 0) && (cos_stokes_rot_2 < 0)) { - i = 2 * acos(-1.) - acos(cos_stokes_rot_1); - } - if ((cos_stokes_rot_1 < 0) && (cos_stokes_rot_2 < 0)) { - i = acos(-1.) + acos(fabs(cos_stokes_rot_1)); - } - if ((cos_stokes_rot_1 < 0) && (cos_stokes_rot_2 > 0)) { - i = acos(-1.) - acos(fabs(cos_stokes_rot_1)); + } else if ((cos_stokes_rot_1 < 0) && (cos_stokes_rot_2 > 0)) { + i = M_PI - acos(fabs(cos_stokes_rot_1)); + } else if ((cos_stokes_rot_1 > 0) && (cos_stokes_rot_2 < 0)) { + i = 2 * M_PI - acos(cos_stokes_rot_1); + } else if ((cos_stokes_rot_1 < 0) && (cos_stokes_rot_2 < 0)) { + i = M_PI + acos(fabs(cos_stokes_rot_1)); } if (cos_stokes_rot_1 == 0) { - i = acos(-1.) / 2.; + i = M_PI / 2.; } if (cos_stokes_rot_2 == 0) { i = 0.0; @@ -991,32 +979,62 @@ auto rot_angle(double *n1, double *n2, double *ref1, double *ref2) -> double { } // Routine to compute the meridian frame axes ref1 and ref2 -void meridian(const double *n, double *ref1, double *ref2) { +void meridian(std::span n, std::span ref1, std::span ref2) { // for ref_1 use (from triple product rule) - - ref1[0] = -1. * n[0] * n[2] / sqrt(n[0] * n[0] + n[1] * n[1]); - ref1[1] = -1. * n[1] * n[2] / sqrt(n[0] * n[0] + n[1] * n[1]); - ref1[2] = (1 - (n[2] * n[2])) / sqrt(n[0] * n[0] + n[1] * n[1]); + const double n_xylen = sqrt(n[0] * n[0] + n[1] * n[1]); + ref1[0] = -1. * n[0] * n[2] / n_xylen; + ref1[1] = -1. * n[1] * n[2] / n_xylen; + ref1[2] = (1 - (n[2] * n[2])) / n_xylen; // for ref_2 use vector product of n_cmf with ref1 + cross_prod(ref1, n, ref2); +} + +static void lorentz(std::span e_rf, std::span n_rf, std::span v, + std::span e_cmf) { + // Lorentz transformations from RF to CMF + + std::array beta = {v[0] / CLIGHT, v[1] / CLIGHT, v[2] / CLIGHT}; + const double vsqr = dot(beta, beta); + + const double gamma_rel = 1. / (sqrt(1 - vsqr)); + + std::array e_par = {dot(e_rf, beta) * beta[0] / (vsqr), dot(e_rf, beta) * beta[1] / (vsqr), + dot(e_rf, beta) * beta[2] / (vsqr)}; + + std::array e_perp = {e_rf[0] - e_par[0], e_rf[1] - e_par[1], e_rf[2] - e_par[2]}; - ref2[0] = n[2] * ref1[1] - n[1] * ref1[2]; - ref2[1] = n[0] * ref1[2] - n[2] * ref1[0]; - ref2[2] = n[1] * ref1[0] - n[0] * ref1[1]; + std::array b_rf = {NAN, NAN, NAN}; + cross_prod(n_rf, e_rf, b_rf); + + // const double b_par[3] = {dot(b_rf, beta) * beta[0] / (vsqr), dot(b_rf, beta) * beta[1] / (vsqr), + // dot(b_rf, beta) * beta[2] / (vsqr)}; + + // const double b_perp[3] = {b_rf[0] - b_par[0], b_rf[1] - b_par[1], b_rf[2] - b_par[2]}; + + std::array v_cr_b = {NAN, NAN, NAN}; + cross_prod(beta, b_rf, v_cr_b); + + // const double v_cr_e[3] = {beta[1] * e_rf[2] - beta[2] * e_rf[1], beta[2] * e_rf[0] - beta[0] * e_rf[2], + // beta[0] * e_rf[1] - beta[1] * e_rf[0]}; + + e_cmf[0] = e_par[0] + gamma_rel * (e_perp[0] + v_cr_b[0]); + e_cmf[1] = e_par[1] + gamma_rel * (e_perp[1] + v_cr_b[1]); + e_cmf[2] = e_par[2] + gamma_rel * (e_perp[2] + v_cr_b[2]); + vec_norm(e_cmf, e_cmf); + + // double b_cmf[3]; + // b_cmf[0] = b_par[0] + gamma_rel * (b_perp[0] - v_cr_e[0]); + // b_cmf[1] = b_par[1] + gamma_rel * (b_perp[1] - v_cr_e[1]); + // b_cmf[2] = b_par[2] + gamma_rel * (b_perp[2] - v_cr_e[2]); + // vec_norm(b_cmf, b_cmf); } // Routine to transform the Stokes Parameters from RF to CMF -void frame_transform(double *n_rf, double *Q, double *U, double *v, double *n_cmf) { - double cos2rot_angle = NAN; - double sin2rot_angle = NAN; - double e_rf[3]; - double e_cmf[3]; - double e_cmf_ref1 = 0.; - double e_cmf_ref2 = 0.; - double theta_rot = 0.; - - double ref1[3]; - double ref2[3]; +void frame_transform(std::span n_rf, double *Q, double *U, std::span v, + std::span n_cmf) { + double ref1[3] = {NAN, NAN, NAN}; + double ref2[3] = {NAN, NAN, NAN}; // Meridian frame in the RF meridian(n_rf, ref1, ref2); @@ -1030,141 +1048,76 @@ void frame_transform(double *n_rf, double *Q, double *U, double *v, double *n_cm double rot_angle = 0; if (p > 0) { - cos2rot_angle = Q0 / p; - sin2rot_angle = U0 / p; + const double cos2rot_angle = Q0 / p; + const double sin2rot_angle = U0 / p; if ((cos2rot_angle > 0) && (sin2rot_angle > 0)) { rot_angle = acos(Q0 / p) / 2.; - } - if ((cos2rot_angle < 0) && (sin2rot_angle > 0)) { - rot_angle = (acos(-1.) - acos(fabs(Q0 / p))) / 2.; - } - if ((cos2rot_angle < 0) && (sin2rot_angle < 0)) { - rot_angle = (acos(-1.) + acos(fabs(Q0 / p))) / 2.; - } - if ((cos2rot_angle > 0) && (sin2rot_angle < 0)) { - rot_angle = (2. * acos(-1.) - acos(fabs(Q0 / p))) / 2.; - } - if (cos2rot_angle == 0) { - rot_angle = 0.25 * acos(-1); + } else if ((cos2rot_angle < 0) && (sin2rot_angle > 0)) { + rot_angle = (M_PI - acos(fabs(cos2rot_angle))) / 2.; + } else if ((cos2rot_angle < 0) && (sin2rot_angle < 0)) { + rot_angle = (M_PI + acos(fabs(cos2rot_angle))) / 2.; + } else if ((cos2rot_angle > 0) && (sin2rot_angle < 0)) { + rot_angle = (2. * M_PI - acos(fabs(cos2rot_angle))) / 2.; + } else if (cos2rot_angle == 0) { + rot_angle = 0.25 * M_PI; if (U0 < 0) { - rot_angle = 0.75 * acos(-1); + rot_angle = 0.75 * M_PI; } } if (sin2rot_angle == 0) { rot_angle = 0.0; if (Q0 < 0) { - rot_angle = 0.5 * acos(-1); + rot_angle = 0.5 * M_PI; } } } // Define electric field by linear combination of ref1 and ref2 (using the angle just computed) - e_rf[0] = cos(rot_angle) * ref1[0] - sin(rot_angle) * ref2[0]; - e_rf[1] = cos(rot_angle) * ref1[1] - sin(rot_angle) * ref2[1]; - e_rf[2] = cos(rot_angle) * ref1[2] - sin(rot_angle) * ref2[2]; + + const double elec_rf[3] = {cos(rot_angle) * ref1[0] - sin(rot_angle) * ref2[0], + cos(rot_angle) * ref1[1] - sin(rot_angle) * ref2[1], + cos(rot_angle) * ref1[2] - sin(rot_angle) * ref2[2]}; // Aberration angle_ab(n_rf, v, n_cmf); + double elec_cmf[3] = {NAN, NAN, NAN}; // Lorentz transformation of E - lorentz(e_rf, n_rf, v, e_cmf); + lorentz(elec_rf, n_rf, v, elec_cmf); // Meridian frame in the CMF meridian(n_cmf, ref1, ref2); // Projection of E onto ref1 and ref2 - e_cmf_ref1 = e_cmf[0] * ref1[0] + e_cmf[1] * ref1[1] + e_cmf[2] * ref1[2]; - e_cmf_ref2 = e_cmf[0] * ref2[0] + e_cmf[1] * ref2[1] + e_cmf[2] * ref2[2]; + const double cosine_elec_ref1 = dot(elec_cmf, ref1); + const double cosine_elec_ref2 = dot(elec_cmf, ref2); // Compute the angle between ref1 and the electric field - if ((e_cmf_ref1 > 0) && (e_cmf_ref2 < 0)) { - theta_rot = acos(e_cmf_ref1); - } - if ((e_cmf_ref1 < 0) && (e_cmf_ref2 < 0)) { - theta_rot = acos(-1.) - acos(fabs(e_cmf_ref1)); - } - if ((e_cmf_ref1 < 0) && (e_cmf_ref2 > 0)) { - theta_rot = acos(-1.) + acos(fabs(e_cmf_ref1)); - } - if ((e_cmf_ref1 > 0) && (e_cmf_ref2 > 0)) { - theta_rot = 2 * acos(-1.) - acos(e_cmf_ref1); + double theta_rot = 0.; + if ((cosine_elec_ref1 > 0) && (cosine_elec_ref2 < 0)) { + theta_rot = acos(cosine_elec_ref1); + } else if ((cosine_elec_ref1 < 0) && (cosine_elec_ref2 > 0)) { + theta_rot = M_PI + acos(fabs(cosine_elec_ref1)); + } else if ((cosine_elec_ref1 < 0) && (cosine_elec_ref2 < 0)) { + theta_rot = M_PI - acos(fabs(cosine_elec_ref1)); + } else if ((cosine_elec_ref1 > 0) && (cosine_elec_ref2 > 0)) { + theta_rot = 2 * M_PI - acos(cosine_elec_ref1); } - if (e_cmf_ref1 == 0) { - theta_rot = acos(-1.) / 2.; + if (cosine_elec_ref1 == 0) { + theta_rot = M_PI / 2.; } - if (e_cmf_ref2 == 0) { + if (cosine_elec_ref2 == 0) { theta_rot = 0.0; } - if (e_cmf_ref1 > 1) { + if (cosine_elec_ref1 > 1) { theta_rot = 0.0; } - if (e_cmf_ref1 < -1) { - theta_rot = acos(-1.); + if (cosine_elec_ref1 < -1) { + theta_rot = M_PI; } // Compute Stokes Parameters in the CMF *Q = cos(2 * theta_rot) * p; *U = sin(2 * theta_rot) * p; -} - -/* ----------------------- Lorentz transformations from RF to CMF --------------------------------------------- */ -void lorentz(const double *e_rf, const double *n_rf, const double *v, double *e_cmf) { - double beta[3]; - double e_par[3]; - double e_perp[3]; - double b_rf[3]; - double b_par[3]; - double b_perp[3]; - double vsqr = NAN; - double gamma_rel = NAN; - double v_cr_b[3]; - double v_cr_e[3]; - double b_cmf[3]; - - beta[0] = v[0] / CLIGHT; - beta[1] = v[1] / CLIGHT; - beta[2] = v[2] / CLIGHT; - vsqr = dot(beta, beta); - - gamma_rel = 1. / (sqrt(1 - vsqr)); - - e_par[0] = (e_rf[0] * beta[0] + e_rf[1] * beta[1] + e_rf[2] * beta[2]) * beta[0] / (vsqr); - e_par[1] = (e_rf[0] * beta[0] + e_rf[1] * beta[1] + e_rf[2] * beta[2]) * beta[1] / (vsqr); - e_par[2] = (e_rf[0] * beta[0] + e_rf[1] * beta[1] + e_rf[2] * beta[2]) * beta[2] / (vsqr); - - e_perp[0] = e_rf[0] - e_par[0]; - e_perp[1] = e_rf[1] - e_par[1]; - e_perp[2] = e_rf[2] - e_par[2]; - - b_rf[0] = n_rf[1] * e_rf[2] - n_rf[2] * e_rf[1]; - b_rf[1] = n_rf[2] * e_rf[0] - n_rf[0] * e_rf[2]; - b_rf[2] = n_rf[0] * e_rf[1] - n_rf[1] * e_rf[0]; - - b_par[0] = (b_rf[0] * beta[0] + b_rf[1] * beta[1] + b_rf[2] * beta[2]) * beta[0] / (vsqr); - b_par[1] = (b_rf[0] * beta[0] + b_rf[1] * beta[1] + b_rf[2] * beta[2]) * beta[1] / (vsqr); - b_par[2] = (b_rf[0] * beta[0] + b_rf[1] * beta[1] + b_rf[2] * beta[2]) * beta[2] / (vsqr); - - b_perp[0] = b_rf[0] - b_par[0]; - b_perp[1] = b_rf[1] - b_par[1]; - b_perp[2] = b_rf[2] - b_par[2]; - - v_cr_b[0] = beta[1] * b_rf[2] - beta[2] * b_rf[1]; - v_cr_b[1] = beta[2] * b_rf[0] - beta[0] * b_rf[2]; - v_cr_b[2] = beta[0] * b_rf[1] - beta[1] * b_rf[0]; - - v_cr_e[0] = beta[1] * e_rf[2] - beta[2] * e_rf[1]; - v_cr_e[1] = beta[2] * e_rf[0] - beta[0] * e_rf[2]; - v_cr_e[2] = beta[0] * e_rf[1] - beta[1] * e_rf[0]; - - e_cmf[0] = e_par[0] + gamma_rel * (e_perp[0] + v_cr_b[0]); - e_cmf[1] = e_par[1] + gamma_rel * (e_perp[1] + v_cr_b[1]); - e_cmf[2] = e_par[2] + gamma_rel * (e_perp[2] + v_cr_b[2]); - - b_cmf[0] = b_par[0] + gamma_rel * (b_perp[0] - v_cr_e[0]); - b_cmf[1] = b_par[1] + gamma_rel * (b_perp[1] - v_cr_e[1]); - b_cmf[2] = b_par[2] + gamma_rel * (b_perp[2] - v_cr_e[2]); - - vec_norm(e_cmf, e_cmf); - vec_norm(b_cmf, b_cmf); } \ No newline at end of file diff --git a/vpkt.h b/vpkt.h index 474013b49..dd385d828 100644 --- a/vpkt.h +++ b/vpkt.h @@ -1,51 +1,38 @@ #ifndef VPKT_H #define VPKT_H -#include +#include #include "artisoptions.h" +#include "packet.h" -double rot_angle(double *n1, double *n2, double *ref1, double *ref2); -void meridian(const double *n, double *ref1, double *ref2); -void frame_transform(double *n_rf, double *Q, double *U, double *v, double *n_cmf); -void lorentz(const double *e_rf, const double *n_rf, const double *v, double *e_cmf); +double rot_angle(std::span n1, std::span n2, std::span ref1, + std::span ref2); +void meridian(std::span n, std::span ref1, std::span ref2); +void frame_transform(std::span n_rf, double *Q, double *U, std::span v, + std::span n_cmf); -void rlc_emiss_vpkt(struct packet *pkt_ptr, double t_current, int bin, double *obs, int realtype); -void add_to_vspecpol(struct packet *pkt_ptr, int bin, int ind, double t_arrive); -void init_vspecpol(); void read_parameterfile_vpkt(); -void write_vspecpol(FILE *specpol_file); -void read_vspecpol(int my_rank, int nts); -void init_vpkt_grid(); -void add_to_vpkt_grid(struct packet *dummy_ptr, const double *vel, int bin_range, int bin, const double *obs); -void write_vpkt_grid(FILE *vpkt_grid_file); -void read_vpkt_grid(FILE *vpkt_grid_file); -int check_tau(const double *tau, const double *tau_max); -int vpkt_call_estimators(struct packet *pkt_ptr, double t_current, int realtype); - -// -------------------------------------------------------------------------------- -// --------------------------- VIRTUAL PACKETS ----------------------------------- -// -------------------------------------------------------------------------------- -#define MRANGE_GRID 5 -#define NY_VGRID 50 -#define NZ_VGRID 50 +void vpkt_init(int nts, int my_rank, int tid, bool continued_from_saved); +void vpkt_call_estimators(struct packet *pkt_ptr, const enum packet_type); +void vpkt_write_timestep(int nts, int my_rank, int tid, bool is_final); + +void vpkt_remove_temp_file(int nts, int my_rank); + +constexpr int VGRID_NY = 50; +constexpr int VGRID_NZ = 50; // FREQUENCY // dlognu = (log(numax) - log(numin)) / VMNUBINS ~ 3.9e-4 (10'000 over 1e14-5e15 Hz) -#define numin_vspec (CLIGHT / 10000 * 1e8) -#define numax_vspec (CLIGHT / 3500 * 1e8) -#define VMNUBINS 2500 +constexpr double VSPEC_NUMIN = CLIGHT / 10000 * 1e8; +constexpr double VSPEC_NUMAX = CLIGHT / 3500 * 1e8; +constexpr int VMNUBINS = 2500; // TIME // dlogt = (log(globals::tmin) - log(globals::tmax)) / VMTBINS ~ 3.69e-2 (111 over 2-120 d) -#define tmin_vspec (10 * DAY) -#define tmax_vspec (30 * DAY) -#define VMTBINS 30 - -// Total number of frequency ranges -#define MRANGE 2 - -extern int vgrid_flag; +constexpr double VSPEC_TIMEMIN = 10 * DAY; +constexpr double VSPEC_TIMEMAX = 30 * DAY; +constexpr int VMTBINS = 30; extern int nvpkt; extern int nvpkt_esc1; // electron scattering event